I: pbuilder: network access will be disabled during build I: Current time: Fri May 10 01:53:18 +14 2024 I: pbuilder-time-stamp: 1715255598 I: Building the build Environment I: extracting base tarball [/var/cache/pbuilder/trixie-reproducible-base.tgz] I: copying local configuration W: --override-config is not set; not updating apt.conf Read the manpage for details. I: mounting /proc filesystem I: mounting /sys filesystem I: creating /{dev,run}/shm I: mounting /dev/pts filesystem I: redirecting /dev/ptmx to /dev/pts/ptmx I: policy-rc.d already exists I: Copying source file I: copying [locust_2.24.0-1.dsc] I: copying [./locust_2.24.0.orig.tar.xz] I: copying [./locust_2.24.0-1.debian.tar.xz] I: Extracting source gpgv: Signature made Wed Mar 13 04:42:15 2024 gpgv: using RSA key B9FAD3192AF3E4A5309D9D39879F3C993801A94F gpgv: Can't check signature: No public key dpkg-source: warning: cannot verify inline signature for ./locust_2.24.0-1.dsc: no acceptable signature found dpkg-source: info: extracting locust in locust-2.24.0 dpkg-source: info: unpacking locust_2.24.0.orig.tar.xz dpkg-source: info: unpacking locust_2.24.0-1.debian.tar.xz I: using fakeroot in build. I: Installing the build-deps I: user script /srv/workspace/pbuilder/227080/tmp/hooks/D01_modify_environment starting debug: Running on codethink02-arm64. I: Changing host+domainname to test build reproducibility I: Adding a custom variable just for the fun of it... I: Changing /bin/sh to bash '/bin/sh' -> '/bin/bash' lrwxrwxrwx 1 root root 9 May 9 11:53 /bin/sh -> /bin/bash I: Setting pbuilder2's login shell to /bin/bash I: Setting pbuilder2's GECOS to second user,second room,second work-phone,second home-phone,second other I: user script /srv/workspace/pbuilder/227080/tmp/hooks/D01_modify_environment finished I: user script /srv/workspace/pbuilder/227080/tmp/hooks/D02_print_environment starting I: set BASH=/bin/sh BASHOPTS=checkwinsize:cmdhist:complete_fullquote:extquote:force_fignore:globasciiranges:globskipdots:hostcomplete:interactive_comments:patsub_replacement:progcomp:promptvars:sourcepath BASH_ALIASES=() BASH_ARGC=() BASH_ARGV=() BASH_CMDS=() BASH_LINENO=([0]="12" [1]="0") BASH_LOADABLES_PATH=/usr/local/lib/bash:/usr/lib/bash:/opt/local/lib/bash:/usr/pkg/lib/bash:/opt/pkg/lib/bash:. BASH_SOURCE=([0]="/tmp/hooks/D02_print_environment" [1]="/tmp/hooks/D02_print_environment") BASH_VERSINFO=([0]="5" [1]="2" [2]="21" [3]="1" [4]="release" [5]="aarch64-unknown-linux-gnu") BASH_VERSION='5.2.21(1)-release' BUILDDIR=/build/reproducible-path BUILDUSERGECOS='second user,second room,second work-phone,second home-phone,second other' BUILDUSERNAME=pbuilder2 BUILD_ARCH=arm64 DEBIAN_FRONTEND=noninteractive DEB_BUILD_OPTIONS='buildinfo=+all reproducible=+all parallel=12 ' DIRSTACK=() DISTRIBUTION=trixie EUID=0 FUNCNAME=([0]="Echo" [1]="main") GROUPS=() HOME=/root HOSTNAME=i-capture-the-hostname HOSTTYPE=aarch64 HOST_ARCH=arm64 IFS=' ' INVOCATION_ID=fe37576a452b46659bdd3cf726239f66 LANG=C LANGUAGE=nl_BE:nl LC_ALL=C MACHTYPE=aarch64-unknown-linux-gnu MAIL=/var/mail/root OPTERR=1 OPTIND=1 OSTYPE=linux-gnu PATH=/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/i/capture/the/path PBCURRENTCOMMANDLINEOPERATION=build PBUILDER_OPERATION=build PBUILDER_PKGDATADIR=/usr/share/pbuilder PBUILDER_PKGLIBDIR=/usr/lib/pbuilder PBUILDER_SYSCONFDIR=/etc PIPESTATUS=([0]="0") POSIXLY_CORRECT=y PPID=227080 PS4='+ ' PWD=/ SHELL=/bin/bash SHELLOPTS=braceexpand:errexit:hashall:interactive-comments:posix SHLVL=3 SUDO_COMMAND='/usr/bin/timeout -k 24.1h 24h /usr/bin/ionice -c 3 /usr/bin/nice -n 11 /usr/bin/unshare --uts -- /usr/sbin/pbuilder --build --configfile /srv/reproducible-results/rbuild-debian/r-b-build.A2tm3BON/pbuilderrc_js7z --distribution trixie --hookdir /etc/pbuilder/rebuild-hooks --debbuildopts -b --basetgz /var/cache/pbuilder/trixie-reproducible-base.tgz --buildresult /srv/reproducible-results/rbuild-debian/r-b-build.A2tm3BON/b2 --logfile b2/build.log locust_2.24.0-1.dsc' SUDO_GID=109 SUDO_UID=104 SUDO_USER=jenkins TERM=unknown TZ=/usr/share/zoneinfo/Etc/GMT-14 UID=0 USER=root _='I: set' http_proxy=http://192.168.101.4:3128 I: uname -a Linux i-capture-the-hostname 6.1.0-21-cloud-arm64 #1 SMP Debian 6.1.90-1 (2024-05-03) aarch64 GNU/Linux I: ls -l /bin lrwxrwxrwx 1 root root 7 May 9 11:24 /bin -> usr/bin I: user script /srv/workspace/pbuilder/227080/tmp/hooks/D02_print_environment finished -> Attempting to satisfy build-dependencies -> Creating pbuilder-satisfydepends-dummy package Package: pbuilder-satisfydepends-dummy Version: 0.invalid.0 Architecture: arm64 Maintainer: Debian Pbuilder Team Description: Dummy package to satisfy dependencies with aptitude - created by pbuilder This package was created automatically by pbuilder to satisfy the build-dependencies of the package being currently built. Depends: debhelper-compat (= 13), pybuild-plugin-pyproject, python3-all, python3-configargparse (>= 1.5.5), python3-cryptography, python3-flask-cors, python3-flask-login (>= 0.6.3), python3-geventhttpclient (>= 2.0.8), python3-msgpack (>= 0.6.2), python3-psutil (>= 5.6.7), python3-pyquery (>= 1.4.3), python3-pytest, python3-requests (>= 2.9.1), python3-retry, python3-roundrobin, python3-setuptools, python3-typing-extensions, python3-zmq (>= 16.0.2) dpkg-deb: building package 'pbuilder-satisfydepends-dummy' in '/tmp/satisfydepends-aptitude/pbuilder-satisfydepends-dummy.deb'. Selecting previously unselected package pbuilder-satisfydepends-dummy. (Reading database ... 19744 files and directories currently installed.) Preparing to unpack .../pbuilder-satisfydepends-dummy.deb ... Unpacking pbuilder-satisfydepends-dummy (0.invalid.0) ... dpkg: pbuilder-satisfydepends-dummy: dependency problems, but configuring anyway as you requested: pbuilder-satisfydepends-dummy depends on debhelper-compat (= 13); however: Package debhelper-compat is not installed. pbuilder-satisfydepends-dummy depends on pybuild-plugin-pyproject; however: Package pybuild-plugin-pyproject is not installed. pbuilder-satisfydepends-dummy depends on python3-all; however: Package python3-all is not installed. pbuilder-satisfydepends-dummy depends on python3-configargparse (>= 1.5.5); however: Package python3-configargparse is not installed. pbuilder-satisfydepends-dummy depends on python3-cryptography; however: Package python3-cryptography is not installed. pbuilder-satisfydepends-dummy depends on python3-flask-cors; however: Package python3-flask-cors is not installed. pbuilder-satisfydepends-dummy depends on python3-flask-login (>= 0.6.3); however: Package python3-flask-login is not installed. pbuilder-satisfydepends-dummy depends on python3-geventhttpclient (>= 2.0.8); however: Package python3-geventhttpclient is not installed. pbuilder-satisfydepends-dummy depends on python3-msgpack (>= 0.6.2); however: Package python3-msgpack is not installed. pbuilder-satisfydepends-dummy depends on python3-psutil (>= 5.6.7); however: Package python3-psutil is not installed. pbuilder-satisfydepends-dummy depends on python3-pyquery (>= 1.4.3); however: Package python3-pyquery is not installed. pbuilder-satisfydepends-dummy depends on python3-pytest; however: Package python3-pytest is not installed. pbuilder-satisfydepends-dummy depends on python3-requests (>= 2.9.1); however: Package python3-requests is not installed. pbuilder-satisfydepends-dummy depends on python3-retry; however: Package python3-retry is not installed. pbuilder-satisfydepends-dummy depends on python3-roundrobin; however: Package python3-roundrobin is not installed. pbuilder-satisfydepends-dummy depends on python3-setuptools; however: Package python3-setuptools is not installed. pbuilder-satisfydepends-dummy depends on python3-typing-extensions; however: Package python3-typing-extensions is not installed. pbuilder-satisfydepends-dummy depends on python3-zmq (>= 16.0.2); however: Package python3-zmq is not installed. Setting up pbuilder-satisfydepends-dummy (0.invalid.0) ... Reading package lists... Building dependency tree... Reading state information... Initializing package states... Writing extended state information... Building tag database... pbuilder-satisfydepends-dummy is already installed at the requested version (0.invalid.0) pbuilder-satisfydepends-dummy is already installed at the requested version (0.invalid.0) The following NEW packages will be installed: autoconf{a} automake{a} autopoint{a} autotools-dev{a} bsdextrautils{a} ca-certificates{a} debhelper{a} dh-autoreconf{a} dh-python{a} dh-strip-nondeterminism{a} dwz{a} file{a} fonts-font-awesome{a} fonts-lato{a} gettext{a} gettext-base{a} groff-base{a} intltool-debian{a} libarchive-zip-perl{a} libbsd0{a} libcares2{a} libcom-err2{a} libdebhelper-perl{a} libelf1t64{a} libev4t64{a} libexpat1{a} libfile-stripnondeterminism-perl{a} libgssapi-krb5-2{a} libicu72{a} libjs-jquery{a} libjs-sphinxdoc{a} libjs-underscore{a} libk5crypto3{a} libkeyutils1{a} libkrb5-3{a} libkrb5support0{a} libmagic-mgc{a} libmagic1t64{a} libnorm1t64{a} libpgm-5.3-0t64{a} libpipeline1{a} libpython3-stdlib{a} libpython3.11-minimal{a} libpython3.11-stdlib{a} libpython3.12-minimal{a} libpython3.12-stdlib{a} libreadline8t64{a} libsodium23{a} libsub-override-perl{a} libtool{a} libuchardet0{a} libxml2{a} libxslt1.1{a} libzmq5{a} m4{a} man-db{a} media-types{a} netbase{a} openssl{a} po-debconf{a} pybuild-plugin-pyproject{a} python3{a} python3-all{a} python3-blinker{a} python3-brotli{a} python3-build{a} python3-certifi{a} python3-cffi-backend{a} python3-chardet{a} python3-charset-normalizer{a} python3-click{a} python3-colorama{a} python3-configargparse{a} python3-cryptography{a} python3-cssselect{a} python3-decorator{a} python3-distutils{a} python3-flask{a} python3-flask-cors{a} python3-flask-login{a} python3-gevent{a} python3-geventhttpclient{a} python3-greenlet{a} python3-idna{a} python3-iniconfig{a} python3-installer{a} python3-itsdangerous{a} python3-jinja2{a} python3-lib2to3{a} python3-lxml{a} python3-markupsafe{a} python3-minimal{a} python3-msgpack{a} python3-packaging{a} python3-pkg-resources{a} python3-pluggy{a} python3-psutil{a} python3-py{a} python3-pyproject-hooks{a} python3-pyquery{a} python3-pytest{a} python3-requests{a} python3-retry{a} python3-roundrobin{a} python3-setuptools{a} python3-six{a} python3-toml{a} python3-typing-extensions{a} python3-urllib3{a} python3-webob{a} python3-werkzeug{a} python3-wheel{a} python3-zmq{a} python3-zope.event{a} python3-zope.interface{a} python3.11{a} python3.11-minimal{a} python3.12{a} python3.12-minimal{a} readline-common{a} sensible-utils{a} sphinx-rtd-theme-common{a} tzdata{a} The following packages are RECOMMENDED but will NOT be installed: curl javascript-common krb5-locales libarchive-cpio-perl libltdl-dev libmail-sendmail-perl lynx python3-asgiref python3-babel python3-bs4 python3-dotenv python3-html5lib python3-openssl python3-pygments python3-pyinotify python3-simplejson wget 0 packages upgraded, 123 newly installed, 0 to remove and 0 not upgraded. Need to get 46.2 MB of archives. After unpacking 194 MB will be used. Writing extended state information... Get: 1 http://deb.debian.org/debian trixie/main arm64 fonts-lato all 2.015-1 [2780 kB] Get: 2 http://deb.debian.org/debian trixie/main arm64 libpython3.11-minimal arm64 3.11.9-1 [813 kB] Get: 3 http://deb.debian.org/debian trixie/main arm64 libexpat1 arm64 2.6.2-1 [88.7 kB] Get: 4 http://deb.debian.org/debian trixie/main arm64 python3.11-minimal arm64 3.11.9-1 [1767 kB] Get: 5 http://deb.debian.org/debian trixie/main arm64 python3-minimal arm64 3.11.8-1 [26.3 kB] Get: 6 http://deb.debian.org/debian trixie/main arm64 media-types all 10.1.0 [26.9 kB] Get: 7 http://deb.debian.org/debian trixie/main arm64 netbase all 6.4 [12.8 kB] Get: 8 http://deb.debian.org/debian trixie/main arm64 tzdata all 2024a-4 [255 kB] Get: 9 http://deb.debian.org/debian trixie/main arm64 readline-common all 8.2-4 [69.3 kB] Get: 10 http://deb.debian.org/debian trixie/main arm64 libreadline8t64 arm64 8.2-4 [157 kB] Get: 11 http://deb.debian.org/debian trixie/main arm64 libpython3.11-stdlib arm64 3.11.9-1 [1775 kB] Get: 12 http://deb.debian.org/debian trixie/main arm64 python3.11 arm64 3.11.9-1 [602 kB] Get: 13 http://deb.debian.org/debian trixie/main arm64 libpython3-stdlib arm64 3.11.8-1 [9332 B] Get: 14 http://deb.debian.org/debian trixie/main arm64 python3 arm64 3.11.8-1 [27.4 kB] Get: 15 http://deb.debian.org/debian trixie/main arm64 libpython3.12-minimal arm64 3.12.3-1 [802 kB] Get: 16 http://deb.debian.org/debian trixie/main arm64 python3.12-minimal arm64 3.12.3-1 [1931 kB] Get: 17 http://deb.debian.org/debian trixie/main arm64 sensible-utils all 0.0.22 [22.4 kB] Get: 18 http://deb.debian.org/debian trixie/main arm64 openssl arm64 3.2.1-3 [1324 kB] Get: 19 http://deb.debian.org/debian trixie/main arm64 ca-certificates all 20240203 [158 kB] Get: 20 http://deb.debian.org/debian trixie/main arm64 libmagic-mgc arm64 1:5.45-3 [314 kB] Get: 21 http://deb.debian.org/debian trixie/main arm64 libmagic1t64 arm64 1:5.45-3 [100 kB] Get: 22 http://deb.debian.org/debian trixie/main arm64 file arm64 1:5.45-3 [43.0 kB] Get: 23 http://deb.debian.org/debian trixie/main arm64 gettext-base arm64 0.21-14+b1 [160 kB] Get: 24 http://deb.debian.org/debian trixie/main arm64 libuchardet0 arm64 0.0.8-1+b1 [69.0 kB] Get: 25 http://deb.debian.org/debian trixie/main arm64 groff-base arm64 1.23.0-4 [1130 kB] Get: 26 http://deb.debian.org/debian trixie/main arm64 bsdextrautils arm64 2.40-8 [93.0 kB] Get: 27 http://deb.debian.org/debian trixie/main arm64 libpipeline1 arm64 1.5.7-2 [36.5 kB] Get: 28 http://deb.debian.org/debian trixie/main arm64 man-db arm64 2.12.1-1 [1394 kB] Get: 29 http://deb.debian.org/debian trixie/main arm64 m4 arm64 1.4.19-4 [277 kB] Get: 30 http://deb.debian.org/debian trixie/main arm64 autoconf all 2.71-3 [332 kB] Get: 31 http://deb.debian.org/debian trixie/main arm64 autotools-dev all 20220109.1 [51.6 kB] Get: 32 http://deb.debian.org/debian trixie/main arm64 automake all 1:1.16.5-1.3 [823 kB] Get: 33 http://deb.debian.org/debian trixie/main arm64 autopoint all 0.21-14 [496 kB] Get: 34 http://deb.debian.org/debian trixie/main arm64 libdebhelper-perl all 13.15.3 [88.0 kB] Get: 35 http://deb.debian.org/debian trixie/main arm64 libtool all 2.4.7-7 [517 kB] Get: 36 http://deb.debian.org/debian trixie/main arm64 dh-autoreconf all 20 [17.1 kB] Get: 37 http://deb.debian.org/debian trixie/main arm64 libarchive-zip-perl all 1.68-1 [104 kB] Get: 38 http://deb.debian.org/debian trixie/main arm64 libsub-override-perl all 0.10-1 [10.6 kB] Get: 39 http://deb.debian.org/debian trixie/main arm64 libfile-stripnondeterminism-perl all 1.13.1-1 [19.4 kB] Get: 40 http://deb.debian.org/debian trixie/main arm64 dh-strip-nondeterminism all 1.13.1-1 [8620 B] Get: 41 http://deb.debian.org/debian trixie/main arm64 libelf1t64 arm64 0.191-1+b1 [187 kB] Get: 42 http://deb.debian.org/debian trixie/main arm64 dwz arm64 0.15-1+b1 [102 kB] Get: 43 http://deb.debian.org/debian trixie/main arm64 libicu72 arm64 72.1-4+b1 [9224 kB] Get: 44 http://deb.debian.org/debian trixie/main arm64 libxml2 arm64 2.9.14+dfsg-1.3+b3 [624 kB] Get: 45 http://deb.debian.org/debian trixie/main arm64 gettext arm64 0.21-14+b1 [1249 kB] Get: 46 http://deb.debian.org/debian trixie/main arm64 intltool-debian all 0.35.0+20060710.6 [22.9 kB] Get: 47 http://deb.debian.org/debian trixie/main arm64 po-debconf all 1.0.21+nmu1 [248 kB] Get: 48 http://deb.debian.org/debian trixie/main arm64 debhelper all 13.15.3 [901 kB] Get: 49 http://deb.debian.org/debian trixie/main arm64 python3-pkg-resources all 68.1.2-2 [241 kB] Get: 50 http://deb.debian.org/debian trixie/main arm64 python3-lib2to3 all 3.12.3-1 [77.6 kB] Get: 51 http://deb.debian.org/debian trixie/main arm64 python3-distutils all 3.12.3-1 [131 kB] Get: 52 http://deb.debian.org/debian trixie/main arm64 python3-setuptools all 68.1.2-2 [468 kB] Get: 53 http://deb.debian.org/debian trixie/main arm64 dh-python all 6.20240422 [107 kB] Get: 54 http://deb.debian.org/debian trixie/main arm64 fonts-font-awesome all 5.0.10+really4.7.0~dfsg-4.1 [517 kB] Get: 55 http://deb.debian.org/debian trixie/main arm64 libbsd0 arm64 0.12.2-1 [129 kB] Get: 56 http://deb.debian.org/debian trixie/main arm64 libcares2 arm64 1.28.1-1 [145 kB] Get: 57 http://deb.debian.org/debian trixie/main arm64 libcom-err2 arm64 1.47.1~rc2-1 [22.5 kB] Get: 58 http://deb.debian.org/debian trixie/main arm64 libev4t64 arm64 1:4.33-2.1 [40.5 kB] Get: 59 http://deb.debian.org/debian trixie/main arm64 libkrb5support0 arm64 1.20.1-6+b1 [33.0 kB] Get: 60 http://deb.debian.org/debian trixie/main arm64 libk5crypto3 arm64 1.20.1-6+b1 [80.5 kB] Get: 61 http://deb.debian.org/debian trixie/main arm64 libkeyutils1 arm64 1.6.3-3 [9112 B] Get: 62 http://deb.debian.org/debian trixie/main arm64 libkrb5-3 arm64 1.20.1-6+b1 [315 kB] Get: 63 http://deb.debian.org/debian trixie/main arm64 libgssapi-krb5-2 arm64 1.20.1-6+b1 [124 kB] Get: 64 http://deb.debian.org/debian trixie/main arm64 libjs-jquery all 3.6.1+dfsg+~3.5.14-1 [326 kB] Get: 65 http://deb.debian.org/debian trixie/main arm64 libjs-underscore all 1.13.4~dfsg+~1.11.4-3 [116 kB] Get: 66 http://deb.debian.org/debian trixie/main arm64 libjs-sphinxdoc all 7.2.6-6 [150 kB] Get: 67 http://deb.debian.org/debian trixie/main arm64 libnorm1t64 arm64 1.5.9+dfsg-3.1 [204 kB] Get: 68 http://deb.debian.org/debian trixie/main arm64 libpgm-5.3-0t64 arm64 5.3.128~dfsg-2.1 [151 kB] Get: 69 http://deb.debian.org/debian trixie/main arm64 libpython3.12-stdlib arm64 3.12.3-1 [1889 kB] Get: 70 http://deb.debian.org/debian trixie/main arm64 libsodium23 arm64 1.0.18-1+b1 [118 kB] Get: 71 http://deb.debian.org/debian trixie/main arm64 libxslt1.1 arm64 1.1.35-1+b1 [221 kB] Get: 72 http://deb.debian.org/debian trixie/main arm64 libzmq5 arm64 4.3.5-1+b2 [251 kB] Get: 73 http://deb.debian.org/debian trixie/main arm64 python3-packaging all 24.0-1 [45.5 kB] Get: 74 http://deb.debian.org/debian trixie/main arm64 python3-pyproject-hooks all 1.0.0-2 [10.6 kB] Get: 75 http://deb.debian.org/debian trixie/main arm64 python3-toml all 0.10.2-1 [16.2 kB] Get: 76 http://deb.debian.org/debian trixie/main arm64 python3-wheel all 0.43.0-1 [52.5 kB] Get: 77 http://deb.debian.org/debian trixie/main arm64 python3-build all 1.2.1-1 [34.1 kB] Get: 78 http://deb.debian.org/debian trixie/main arm64 python3-installer all 0.7.0+dfsg1-3 [18.6 kB] Get: 79 http://deb.debian.org/debian trixie/main arm64 pybuild-plugin-pyproject all 6.20240422 [11.1 kB] Get: 80 http://deb.debian.org/debian trixie/main arm64 python3.12 arm64 3.12.3-1 [659 kB] Get: 81 http://deb.debian.org/debian trixie/main arm64 python3-all arm64 3.11.8-1 [1056 B] Get: 82 http://deb.debian.org/debian trixie/main arm64 python3-blinker all 1.8.1-1 [13.1 kB] Get: 83 http://deb.debian.org/debian trixie/main arm64 python3-brotli arm64 1.1.0-2+b3 [316 kB] Get: 84 http://deb.debian.org/debian trixie/main arm64 python3-certifi all 2023.11.17-1 [155 kB] Get: 85 http://deb.debian.org/debian trixie/main arm64 python3-cffi-backend arm64 1.16.0-2+b2 [109 kB] Get: 86 http://deb.debian.org/debian trixie/main arm64 python3-chardet all 5.2.0+dfsg-1 [107 kB] Get: 87 http://deb.debian.org/debian trixie/main arm64 python3-charset-normalizer all 3.3.2-1 [51.6 kB] Get: 88 http://deb.debian.org/debian trixie/main arm64 python3-colorama all 0.4.6-4 [36.2 kB] Get: 89 http://deb.debian.org/debian trixie/main arm64 python3-click all 8.1.7-1 [94.0 kB] Get: 90 http://deb.debian.org/debian trixie/main arm64 python3-configargparse all 1.7-1 [31.3 kB] Get: 91 http://deb.debian.org/debian trixie/main arm64 python3-cryptography arm64 42.0.5-2 [1050 kB] Get: 92 http://deb.debian.org/debian trixie/main arm64 python3-cssselect all 1.2.0-4 [21.7 kB] Get: 93 http://deb.debian.org/debian trixie/main arm64 python3-decorator all 5.1.1-5 [15.1 kB] Get: 94 http://deb.debian.org/debian trixie/main arm64 python3-itsdangerous all 2.1.2-4 [17.1 kB] Get: 95 http://deb.debian.org/debian trixie/main arm64 python3-markupsafe arm64 2.1.5-1 [14.6 kB] Get: 96 http://deb.debian.org/debian trixie/main arm64 python3-jinja2 all 3.1.3-1 [119 kB] Get: 97 http://deb.debian.org/debian trixie/main arm64 python3-werkzeug all 3.0.2-1 [206 kB] Get: 98 http://deb.debian.org/debian trixie/main arm64 python3-flask all 3.0.3-1 [104 kB] Get: 99 http://deb.debian.org/debian trixie/main arm64 sphinx-rtd-theme-common all 2.0.0+dfsg-1 [1021 kB] Get: 100 http://deb.debian.org/debian trixie/main arm64 python3-flask-cors all 4.0.0-1 [44.1 kB] Get: 101 http://deb.debian.org/debian trixie/main arm64 python3-flask-login all 0.6.3-2 [22.8 kB] Get: 102 http://deb.debian.org/debian trixie/main arm64 python3-greenlet arm64 3.0.1-3 [171 kB] Get: 103 http://deb.debian.org/debian trixie/main arm64 python3-zope.event all 5.0-0.1 [8164 B] Get: 104 http://deb.debian.org/debian trixie/main arm64 python3-zope.interface arm64 6.1-1 [153 kB] Get: 105 http://deb.debian.org/debian trixie/main arm64 python3-gevent arm64 24.2.1-0.1+b1 [1038 kB] Get: 106 http://deb.debian.org/debian trixie/main arm64 python3-six all 1.16.0-6 [16.3 kB] Get: 107 http://deb.debian.org/debian trixie/main arm64 python3-geventhttpclient arm64 2.0.11-2 [40.3 kB] Get: 108 http://deb.debian.org/debian trixie/main arm64 python3-idna all 3.6-2 [37.0 kB] Get: 109 http://deb.debian.org/debian trixie/main arm64 python3-iniconfig all 1.1.1-2 [6396 B] Get: 110 http://deb.debian.org/debian trixie/main arm64 python3-lxml arm64 5.1.0-1 [1810 kB] Get: 111 http://deb.debian.org/debian trixie/main arm64 python3-msgpack arm64 1.0.3-3+b1 [87.4 kB] Get: 112 http://deb.debian.org/debian trixie/main arm64 python3-pluggy all 1.5.0-1 [26.9 kB] Get: 113 http://deb.debian.org/debian trixie/main arm64 python3-psutil arm64 5.9.8-2 [225 kB] Get: 114 http://deb.debian.org/debian trixie/main arm64 python3-py all 1.11.0-2 [88.7 kB] Get: 115 http://deb.debian.org/debian trixie/main arm64 python3-webob all 1:1.8.7-1 [88.2 kB] Get: 116 http://deb.debian.org/debian trixie/main arm64 python3-pyquery all 1.4.3-1 [23.1 kB] Get: 117 http://deb.debian.org/debian trixie/main arm64 python3-pytest all 7.4.4-3 [239 kB] Get: 118 http://deb.debian.org/debian trixie/main arm64 python3-urllib3 all 1.26.18-2 [116 kB] Get: 119 http://deb.debian.org/debian trixie/main arm64 python3-requests all 2.31.0+dfsg-1 [68.6 kB] Get: 120 http://deb.debian.org/debian trixie/main arm64 python3-retry all 0.9.2-2 [7020 B] Get: 121 http://deb.debian.org/debian trixie/main arm64 python3-roundrobin all 0.0.4-3 [4364 B] Get: 122 http://deb.debian.org/debian trixie/main arm64 python3-typing-extensions all 4.10.0-1 [66.2 kB] Get: 123 http://deb.debian.org/debian trixie/main arm64 python3-zmq arm64 24.0.1-5+b1 [329 kB] Fetched 46.2 MB in 0s (133 MB/s) debconf: delaying package configuration, since apt-utils is not installed Selecting previously unselected package fonts-lato. (Reading database ... (Reading database ... 5% (Reading database ... 10% (Reading database ... 15% (Reading database ... 20% (Reading database ... 25% (Reading database ... 30% (Reading database ... 35% (Reading database ... 40% (Reading database ... 45% (Reading database ... 50% (Reading database ... 55% (Reading database ... 60% (Reading database ... 65% (Reading database ... 70% (Reading database ... 75% (Reading database ... 80% (Reading database ... 85% (Reading database ... 90% (Reading database ... 95% (Reading database ... 100% (Reading database ... 19744 files and directories currently installed.) Preparing to unpack .../fonts-lato_2.015-1_all.deb ... Unpacking fonts-lato (2.015-1) ... Selecting previously unselected package libpython3.11-minimal:arm64. Preparing to unpack .../libpython3.11-minimal_3.11.9-1_arm64.deb ... Unpacking libpython3.11-minimal:arm64 (3.11.9-1) ... Selecting previously unselected package libexpat1:arm64. Preparing to unpack .../libexpat1_2.6.2-1_arm64.deb ... Unpacking libexpat1:arm64 (2.6.2-1) ... Selecting previously unselected package python3.11-minimal. Preparing to unpack .../python3.11-minimal_3.11.9-1_arm64.deb ... Unpacking python3.11-minimal (3.11.9-1) ... Setting up libpython3.11-minimal:arm64 (3.11.9-1) ... Setting up libexpat1:arm64 (2.6.2-1) ... Setting up python3.11-minimal (3.11.9-1) ... Selecting previously unselected package python3-minimal. (Reading database ... (Reading database ... 5% (Reading database ... 10% (Reading database ... 15% (Reading database ... 20% (Reading database ... 25% (Reading database ... 30% (Reading database ... 35% (Reading database ... 40% (Reading database ... 45% (Reading database ... 50% (Reading database ... 55% (Reading database ... 60% (Reading database ... 65% (Reading database ... 70% (Reading database ... 75% (Reading database ... 80% (Reading database ... 85% (Reading database ... 90% (Reading database ... 95% (Reading database ... 100% (Reading database ... 20086 files and directories currently installed.) Preparing to unpack .../0-python3-minimal_3.11.8-1_arm64.deb ... Unpacking python3-minimal (3.11.8-1) ... Selecting previously unselected package media-types. Preparing to unpack .../1-media-types_10.1.0_all.deb ... Unpacking media-types (10.1.0) ... Selecting previously unselected package netbase. Preparing to unpack .../2-netbase_6.4_all.deb ... Unpacking netbase (6.4) ... Selecting previously unselected package tzdata. Preparing to unpack .../3-tzdata_2024a-4_all.deb ... Unpacking tzdata (2024a-4) ... Selecting previously unselected package readline-common. Preparing to unpack .../4-readline-common_8.2-4_all.deb ... Unpacking readline-common (8.2-4) ... Selecting previously unselected package libreadline8t64:arm64. Preparing to unpack .../5-libreadline8t64_8.2-4_arm64.deb ... Adding 'diversion of /lib/aarch64-linux-gnu/libhistory.so.8 to /lib/aarch64-linux-gnu/libhistory.so.8.usr-is-merged by libreadline8t64' Adding 'diversion of /lib/aarch64-linux-gnu/libhistory.so.8.2 to /lib/aarch64-linux-gnu/libhistory.so.8.2.usr-is-merged by libreadline8t64' Adding 'diversion of /lib/aarch64-linux-gnu/libreadline.so.8 to /lib/aarch64-linux-gnu/libreadline.so.8.usr-is-merged by libreadline8t64' Adding 'diversion of /lib/aarch64-linux-gnu/libreadline.so.8.2 to /lib/aarch64-linux-gnu/libreadline.so.8.2.usr-is-merged by libreadline8t64' Unpacking libreadline8t64:arm64 (8.2-4) ... Selecting previously unselected package libpython3.11-stdlib:arm64. Preparing to unpack .../6-libpython3.11-stdlib_3.11.9-1_arm64.deb ... Unpacking libpython3.11-stdlib:arm64 (3.11.9-1) ... Selecting previously unselected package python3.11. Preparing to unpack .../7-python3.11_3.11.9-1_arm64.deb ... Unpacking python3.11 (3.11.9-1) ... Selecting previously unselected package libpython3-stdlib:arm64. Preparing to unpack .../8-libpython3-stdlib_3.11.8-1_arm64.deb ... Unpacking libpython3-stdlib:arm64 (3.11.8-1) ... Setting up python3-minimal (3.11.8-1) ... Selecting previously unselected package python3. (Reading database ... (Reading database ... 5% (Reading database ... 10% (Reading database ... 15% (Reading database ... 20% (Reading database ... 25% (Reading database ... 30% (Reading database ... 35% (Reading database ... 40% (Reading database ... 45% (Reading database ... 50% (Reading database ... 55% (Reading database ... 60% (Reading database ... 65% (Reading database ... 70% (Reading database ... 75% (Reading database ... 80% (Reading database ... 85% (Reading database ... 90% (Reading database ... 95% (Reading database ... 100% (Reading database ... 21078 files and directories currently installed.) Preparing to unpack .../000-python3_3.11.8-1_arm64.deb ... Unpacking python3 (3.11.8-1) ... Selecting previously unselected package libpython3.12-minimal:arm64. Preparing to unpack .../001-libpython3.12-minimal_3.12.3-1_arm64.deb ... Unpacking libpython3.12-minimal:arm64 (3.12.3-1) ... Selecting previously unselected package python3.12-minimal. Preparing to unpack .../002-python3.12-minimal_3.12.3-1_arm64.deb ... Unpacking python3.12-minimal (3.12.3-1) ... Selecting previously unselected package sensible-utils. Preparing to unpack .../003-sensible-utils_0.0.22_all.deb ... Unpacking sensible-utils (0.0.22) ... Selecting previously unselected package openssl. Preparing to unpack .../004-openssl_3.2.1-3_arm64.deb ... Unpacking openssl (3.2.1-3) ... Selecting previously unselected package ca-certificates. Preparing to unpack .../005-ca-certificates_20240203_all.deb ... Unpacking ca-certificates (20240203) ... Selecting previously unselected package libmagic-mgc. Preparing to unpack .../006-libmagic-mgc_1%3a5.45-3_arm64.deb ... Unpacking libmagic-mgc (1:5.45-3) ... Selecting previously unselected package libmagic1t64:arm64. Preparing to unpack .../007-libmagic1t64_1%3a5.45-3_arm64.deb ... Unpacking libmagic1t64:arm64 (1:5.45-3) ... Selecting previously unselected package file. Preparing to unpack .../008-file_1%3a5.45-3_arm64.deb ... Unpacking file (1:5.45-3) ... Selecting previously unselected package gettext-base. Preparing to unpack .../009-gettext-base_0.21-14+b1_arm64.deb ... Unpacking gettext-base (0.21-14+b1) ... Selecting previously unselected package libuchardet0:arm64. Preparing to unpack .../010-libuchardet0_0.0.8-1+b1_arm64.deb ... Unpacking libuchardet0:arm64 (0.0.8-1+b1) ... Selecting previously unselected package groff-base. Preparing to unpack .../011-groff-base_1.23.0-4_arm64.deb ... Unpacking groff-base (1.23.0-4) ... Selecting previously unselected package bsdextrautils. Preparing to unpack .../012-bsdextrautils_2.40-8_arm64.deb ... Unpacking bsdextrautils (2.40-8) ... Selecting previously unselected package libpipeline1:arm64. Preparing to unpack .../013-libpipeline1_1.5.7-2_arm64.deb ... Unpacking libpipeline1:arm64 (1.5.7-2) ... Selecting previously unselected package man-db. Preparing to unpack .../014-man-db_2.12.1-1_arm64.deb ... Unpacking man-db (2.12.1-1) ... Selecting previously unselected package m4. Preparing to unpack .../015-m4_1.4.19-4_arm64.deb ... Unpacking m4 (1.4.19-4) ... Selecting previously unselected package autoconf. Preparing to unpack .../016-autoconf_2.71-3_all.deb ... Unpacking autoconf (2.71-3) ... Selecting previously unselected package autotools-dev. Preparing to unpack .../017-autotools-dev_20220109.1_all.deb ... Unpacking autotools-dev (20220109.1) ... Selecting previously unselected package automake. Preparing to unpack .../018-automake_1%3a1.16.5-1.3_all.deb ... Unpacking automake (1:1.16.5-1.3) ... Selecting previously unselected package autopoint. Preparing to unpack .../019-autopoint_0.21-14_all.deb ... Unpacking autopoint (0.21-14) ... Selecting previously unselected package libdebhelper-perl. Preparing to unpack .../020-libdebhelper-perl_13.15.3_all.deb ... Unpacking libdebhelper-perl (13.15.3) ... Selecting previously unselected package libtool. Preparing to unpack .../021-libtool_2.4.7-7_all.deb ... Unpacking libtool (2.4.7-7) ... Selecting previously unselected package dh-autoreconf. Preparing to unpack .../022-dh-autoreconf_20_all.deb ... Unpacking dh-autoreconf (20) ... Selecting previously unselected package libarchive-zip-perl. Preparing to unpack .../023-libarchive-zip-perl_1.68-1_all.deb ... Unpacking libarchive-zip-perl (1.68-1) ... Selecting previously unselected package libsub-override-perl. Preparing to unpack .../024-libsub-override-perl_0.10-1_all.deb ... Unpacking libsub-override-perl (0.10-1) ... Selecting previously unselected package libfile-stripnondeterminism-perl. Preparing to unpack .../025-libfile-stripnondeterminism-perl_1.13.1-1_all.deb ... Unpacking libfile-stripnondeterminism-perl (1.13.1-1) ... Selecting previously unselected package dh-strip-nondeterminism. Preparing to unpack .../026-dh-strip-nondeterminism_1.13.1-1_all.deb ... Unpacking dh-strip-nondeterminism (1.13.1-1) ... Selecting previously unselected package libelf1t64:arm64. Preparing to unpack .../027-libelf1t64_0.191-1+b1_arm64.deb ... Unpacking libelf1t64:arm64 (0.191-1+b1) ... Selecting previously unselected package dwz. Preparing to unpack .../028-dwz_0.15-1+b1_arm64.deb ... Unpacking dwz (0.15-1+b1) ... Selecting previously unselected package libicu72:arm64. Preparing to unpack .../029-libicu72_72.1-4+b1_arm64.deb ... Unpacking libicu72:arm64 (72.1-4+b1) ... Selecting previously unselected package libxml2:arm64. Preparing to unpack .../030-libxml2_2.9.14+dfsg-1.3+b3_arm64.deb ... Unpacking libxml2:arm64 (2.9.14+dfsg-1.3+b3) ... Selecting previously unselected package gettext. Preparing to unpack .../031-gettext_0.21-14+b1_arm64.deb ... Unpacking gettext (0.21-14+b1) ... Selecting previously unselected package intltool-debian. Preparing to unpack .../032-intltool-debian_0.35.0+20060710.6_all.deb ... Unpacking intltool-debian (0.35.0+20060710.6) ... Selecting previously unselected package po-debconf. Preparing to unpack .../033-po-debconf_1.0.21+nmu1_all.deb ... Unpacking po-debconf (1.0.21+nmu1) ... Selecting previously unselected package debhelper. Preparing to unpack .../034-debhelper_13.15.3_all.deb ... Unpacking debhelper (13.15.3) ... Selecting previously unselected package python3-pkg-resources. Preparing to unpack .../035-python3-pkg-resources_68.1.2-2_all.deb ... Unpacking python3-pkg-resources (68.1.2-2) ... Selecting previously unselected package python3-lib2to3. Preparing to unpack .../036-python3-lib2to3_3.12.3-1_all.deb ... Unpacking python3-lib2to3 (3.12.3-1) ... Selecting previously unselected package python3-distutils. Preparing to unpack .../037-python3-distutils_3.12.3-1_all.deb ... Unpacking python3-distutils (3.12.3-1) ... Selecting previously unselected package python3-setuptools. Preparing to unpack .../038-python3-setuptools_68.1.2-2_all.deb ... Unpacking python3-setuptools (68.1.2-2) ... Selecting previously unselected package dh-python. Preparing to unpack .../039-dh-python_6.20240422_all.deb ... Unpacking dh-python (6.20240422) ... Selecting previously unselected package fonts-font-awesome. Preparing to unpack .../040-fonts-font-awesome_5.0.10+really4.7.0~dfsg-4.1_all.deb ... Unpacking fonts-font-awesome (5.0.10+really4.7.0~dfsg-4.1) ... Selecting previously unselected package libbsd0:arm64. Preparing to unpack .../041-libbsd0_0.12.2-1_arm64.deb ... Unpacking libbsd0:arm64 (0.12.2-1) ... Selecting previously unselected package libcares2:arm64. Preparing to unpack .../042-libcares2_1.28.1-1_arm64.deb ... Unpacking libcares2:arm64 (1.28.1-1) ... Selecting previously unselected package libcom-err2:arm64. Preparing to unpack .../043-libcom-err2_1.47.1~rc2-1_arm64.deb ... Unpacking libcom-err2:arm64 (1.47.1~rc2-1) ... Selecting previously unselected package libev4t64:arm64. Preparing to unpack .../044-libev4t64_1%3a4.33-2.1_arm64.deb ... Unpacking libev4t64:arm64 (1:4.33-2.1) ... Selecting previously unselected package libkrb5support0:arm64. Preparing to unpack .../045-libkrb5support0_1.20.1-6+b1_arm64.deb ... Unpacking libkrb5support0:arm64 (1.20.1-6+b1) ... Selecting previously unselected package libk5crypto3:arm64. Preparing to unpack .../046-libk5crypto3_1.20.1-6+b1_arm64.deb ... Unpacking libk5crypto3:arm64 (1.20.1-6+b1) ... Selecting previously unselected package libkeyutils1:arm64. Preparing to unpack .../047-libkeyutils1_1.6.3-3_arm64.deb ... Unpacking libkeyutils1:arm64 (1.6.3-3) ... Selecting previously unselected package libkrb5-3:arm64. Preparing to unpack .../048-libkrb5-3_1.20.1-6+b1_arm64.deb ... Unpacking libkrb5-3:arm64 (1.20.1-6+b1) ... Selecting previously unselected package libgssapi-krb5-2:arm64. Preparing to unpack .../049-libgssapi-krb5-2_1.20.1-6+b1_arm64.deb ... Unpacking libgssapi-krb5-2:arm64 (1.20.1-6+b1) ... Selecting previously unselected package libjs-jquery. Preparing to unpack .../050-libjs-jquery_3.6.1+dfsg+~3.5.14-1_all.deb ... Unpacking libjs-jquery (3.6.1+dfsg+~3.5.14-1) ... Selecting previously unselected package libjs-underscore. Preparing to unpack .../051-libjs-underscore_1.13.4~dfsg+~1.11.4-3_all.deb ... Unpacking libjs-underscore (1.13.4~dfsg+~1.11.4-3) ... Selecting previously unselected package libjs-sphinxdoc. Preparing to unpack .../052-libjs-sphinxdoc_7.2.6-6_all.deb ... Unpacking libjs-sphinxdoc (7.2.6-6) ... Selecting previously unselected package libnorm1t64:arm64. Preparing to unpack .../053-libnorm1t64_1.5.9+dfsg-3.1_arm64.deb ... Unpacking libnorm1t64:arm64 (1.5.9+dfsg-3.1) ... Selecting previously unselected package libpgm-5.3-0t64:arm64. Preparing to unpack .../054-libpgm-5.3-0t64_5.3.128~dfsg-2.1_arm64.deb ... Unpacking libpgm-5.3-0t64:arm64 (5.3.128~dfsg-2.1) ... Selecting previously unselected package libpython3.12-stdlib:arm64. Preparing to unpack .../055-libpython3.12-stdlib_3.12.3-1_arm64.deb ... Unpacking libpython3.12-stdlib:arm64 (3.12.3-1) ... Selecting previously unselected package libsodium23:arm64. Preparing to unpack .../056-libsodium23_1.0.18-1+b1_arm64.deb ... Unpacking libsodium23:arm64 (1.0.18-1+b1) ... Selecting previously unselected package libxslt1.1:arm64. Preparing to unpack .../057-libxslt1.1_1.1.35-1+b1_arm64.deb ... Unpacking libxslt1.1:arm64 (1.1.35-1+b1) ... Selecting previously unselected package libzmq5:arm64. Preparing to unpack .../058-libzmq5_4.3.5-1+b2_arm64.deb ... Unpacking libzmq5:arm64 (4.3.5-1+b2) ... Selecting previously unselected package python3-packaging. Preparing to unpack .../059-python3-packaging_24.0-1_all.deb ... Unpacking python3-packaging (24.0-1) ... Selecting previously unselected package python3-pyproject-hooks. Preparing to unpack .../060-python3-pyproject-hooks_1.0.0-2_all.deb ... Unpacking python3-pyproject-hooks (1.0.0-2) ... Selecting previously unselected package python3-toml. Preparing to unpack .../061-python3-toml_0.10.2-1_all.deb ... Unpacking python3-toml (0.10.2-1) ... Selecting previously unselected package python3-wheel. Preparing to unpack .../062-python3-wheel_0.43.0-1_all.deb ... Unpacking python3-wheel (0.43.0-1) ... Selecting previously unselected package python3-build. Preparing to unpack .../063-python3-build_1.2.1-1_all.deb ... Unpacking python3-build (1.2.1-1) ... Selecting previously unselected package python3-installer. Preparing to unpack .../064-python3-installer_0.7.0+dfsg1-3_all.deb ... Unpacking python3-installer (0.7.0+dfsg1-3) ... Selecting previously unselected package pybuild-plugin-pyproject. Preparing to unpack .../065-pybuild-plugin-pyproject_6.20240422_all.deb ... Unpacking pybuild-plugin-pyproject (6.20240422) ... Selecting previously unselected package python3.12. Preparing to unpack .../066-python3.12_3.12.3-1_arm64.deb ... Unpacking python3.12 (3.12.3-1) ... Selecting previously unselected package python3-all. Preparing to unpack .../067-python3-all_3.11.8-1_arm64.deb ... Unpacking python3-all (3.11.8-1) ... Selecting previously unselected package python3-blinker. Preparing to unpack .../068-python3-blinker_1.8.1-1_all.deb ... Unpacking python3-blinker (1.8.1-1) ... Selecting previously unselected package python3-brotli. Preparing to unpack .../069-python3-brotli_1.1.0-2+b3_arm64.deb ... Unpacking python3-brotli (1.1.0-2+b3) ... Selecting previously unselected package python3-certifi. Preparing to unpack .../070-python3-certifi_2023.11.17-1_all.deb ... Unpacking python3-certifi (2023.11.17-1) ... Selecting previously unselected package python3-cffi-backend:arm64. Preparing to unpack .../071-python3-cffi-backend_1.16.0-2+b2_arm64.deb ... Unpacking python3-cffi-backend:arm64 (1.16.0-2+b2) ... Selecting previously unselected package python3-chardet. Preparing to unpack .../072-python3-chardet_5.2.0+dfsg-1_all.deb ... Unpacking python3-chardet (5.2.0+dfsg-1) ... Selecting previously unselected package python3-charset-normalizer. Preparing to unpack .../073-python3-charset-normalizer_3.3.2-1_all.deb ... Unpacking python3-charset-normalizer (3.3.2-1) ... Selecting previously unselected package python3-colorama. Preparing to unpack .../074-python3-colorama_0.4.6-4_all.deb ... Unpacking python3-colorama (0.4.6-4) ... Selecting previously unselected package python3-click. Preparing to unpack .../075-python3-click_8.1.7-1_all.deb ... Unpacking python3-click (8.1.7-1) ... Selecting previously unselected package python3-configargparse. Preparing to unpack .../076-python3-configargparse_1.7-1_all.deb ... Unpacking python3-configargparse (1.7-1) ... Selecting previously unselected package python3-cryptography. Preparing to unpack .../077-python3-cryptography_42.0.5-2_arm64.deb ... Unpacking python3-cryptography (42.0.5-2) ... Selecting previously unselected package python3-cssselect. Preparing to unpack .../078-python3-cssselect_1.2.0-4_all.deb ... Unpacking python3-cssselect (1.2.0-4) ... Selecting previously unselected package python3-decorator. Preparing to unpack .../079-python3-decorator_5.1.1-5_all.deb ... Unpacking python3-decorator (5.1.1-5) ... Selecting previously unselected package python3-itsdangerous. Preparing to unpack .../080-python3-itsdangerous_2.1.2-4_all.deb ... Unpacking python3-itsdangerous (2.1.2-4) ... Selecting previously unselected package python3-markupsafe. Preparing to unpack .../081-python3-markupsafe_2.1.5-1_arm64.deb ... Unpacking python3-markupsafe (2.1.5-1) ... Selecting previously unselected package python3-jinja2. Preparing to unpack .../082-python3-jinja2_3.1.3-1_all.deb ... Unpacking python3-jinja2 (3.1.3-1) ... Selecting previously unselected package python3-werkzeug. Preparing to unpack .../083-python3-werkzeug_3.0.2-1_all.deb ... Unpacking python3-werkzeug (3.0.2-1) ... Selecting previously unselected package python3-flask. Preparing to unpack .../084-python3-flask_3.0.3-1_all.deb ... Unpacking python3-flask (3.0.3-1) ... Selecting previously unselected package sphinx-rtd-theme-common. Preparing to unpack .../085-sphinx-rtd-theme-common_2.0.0+dfsg-1_all.deb ... Unpacking sphinx-rtd-theme-common (2.0.0+dfsg-1) ... Selecting previously unselected package python3-flask-cors. Preparing to unpack .../086-python3-flask-cors_4.0.0-1_all.deb ... Unpacking python3-flask-cors (4.0.0-1) ... Selecting previously unselected package python3-flask-login. Preparing to unpack .../087-python3-flask-login_0.6.3-2_all.deb ... Unpacking python3-flask-login (0.6.3-2) ... Selecting previously unselected package python3-greenlet. Preparing to unpack .../088-python3-greenlet_3.0.1-3_arm64.deb ... Unpacking python3-greenlet (3.0.1-3) ... Selecting previously unselected package python3-zope.event. Preparing to unpack .../089-python3-zope.event_5.0-0.1_all.deb ... Unpacking python3-zope.event (5.0-0.1) ... Selecting previously unselected package python3-zope.interface. Preparing to unpack .../090-python3-zope.interface_6.1-1_arm64.deb ... Unpacking python3-zope.interface (6.1-1) ... Selecting previously unselected package python3-gevent. Preparing to unpack .../091-python3-gevent_24.2.1-0.1+b1_arm64.deb ... Unpacking python3-gevent (24.2.1-0.1+b1) ... Selecting previously unselected package python3-six. Preparing to unpack .../092-python3-six_1.16.0-6_all.deb ... Unpacking python3-six (1.16.0-6) ... Selecting previously unselected package python3-geventhttpclient. Preparing to unpack .../093-python3-geventhttpclient_2.0.11-2_arm64.deb ... Unpacking python3-geventhttpclient (2.0.11-2) ... Selecting previously unselected package python3-idna. Preparing to unpack .../094-python3-idna_3.6-2_all.deb ... Unpacking python3-idna (3.6-2) ... Selecting previously unselected package python3-iniconfig. Preparing to unpack .../095-python3-iniconfig_1.1.1-2_all.deb ... Unpacking python3-iniconfig (1.1.1-2) ... Selecting previously unselected package python3-lxml:arm64. Preparing to unpack .../096-python3-lxml_5.1.0-1_arm64.deb ... Unpacking python3-lxml:arm64 (5.1.0-1) ... Selecting previously unselected package python3-msgpack. Preparing to unpack .../097-python3-msgpack_1.0.3-3+b1_arm64.deb ... Unpacking python3-msgpack (1.0.3-3+b1) ... Selecting previously unselected package python3-pluggy. Preparing to unpack .../098-python3-pluggy_1.5.0-1_all.deb ... Unpacking python3-pluggy (1.5.0-1) ... Selecting previously unselected package python3-psutil. Preparing to unpack .../099-python3-psutil_5.9.8-2_arm64.deb ... Unpacking python3-psutil (5.9.8-2) ... Selecting previously unselected package python3-py. Preparing to unpack .../100-python3-py_1.11.0-2_all.deb ... Unpacking python3-py (1.11.0-2) ... Selecting previously unselected package python3-webob. Preparing to unpack .../101-python3-webob_1%3a1.8.7-1_all.deb ... Unpacking python3-webob (1:1.8.7-1) ... Selecting previously unselected package python3-pyquery. Preparing to unpack .../102-python3-pyquery_1.4.3-1_all.deb ... Unpacking python3-pyquery (1.4.3-1) ... Selecting previously unselected package python3-pytest. Preparing to unpack .../103-python3-pytest_7.4.4-3_all.deb ... Unpacking python3-pytest (7.4.4-3) ... Selecting previously unselected package python3-urllib3. Preparing to unpack .../104-python3-urllib3_1.26.18-2_all.deb ... Unpacking python3-urllib3 (1.26.18-2) ... Selecting previously unselected package python3-requests. Preparing to unpack .../105-python3-requests_2.31.0+dfsg-1_all.deb ... Unpacking python3-requests (2.31.0+dfsg-1) ... Selecting previously unselected package python3-retry. Preparing to unpack .../106-python3-retry_0.9.2-2_all.deb ... Unpacking python3-retry (0.9.2-2) ... Selecting previously unselected package python3-roundrobin. Preparing to unpack .../107-python3-roundrobin_0.0.4-3_all.deb ... Unpacking python3-roundrobin (0.0.4-3) ... Selecting previously unselected package python3-typing-extensions. Preparing to unpack .../108-python3-typing-extensions_4.10.0-1_all.deb ... Unpacking python3-typing-extensions (4.10.0-1) ... Selecting previously unselected package python3-zmq. Preparing to unpack .../109-python3-zmq_24.0.1-5+b1_arm64.deb ... Unpacking python3-zmq (24.0.1-5+b1) ... Setting up media-types (10.1.0) ... Setting up libpipeline1:arm64 (1.5.7-2) ... Setting up libev4t64:arm64 (1:4.33-2.1) ... Setting up libnorm1t64:arm64 (1.5.9+dfsg-3.1) ... Setting up libkeyutils1:arm64 (1.6.3-3) ... Setting up fonts-lato (2.015-1) ... Setting up libsodium23:arm64 (1.0.18-1+b1) ... Setting up libicu72:arm64 (72.1-4+b1) ... Setting up bsdextrautils (2.40-8) ... Setting up libmagic-mgc (1:5.45-3) ... Setting up libarchive-zip-perl (1.68-1) ... Setting up libdebhelper-perl (13.15.3) ... Setting up libmagic1t64:arm64 (1:5.45-3) ... Setting up libpython3.12-minimal:arm64 (3.12.3-1) ... Setting up gettext-base (0.21-14+b1) ... Setting up m4 (1.4.19-4) ... Setting up libcom-err2:arm64 (1.47.1~rc2-1) ... Setting up file (1:5.45-3) ... Setting up libelf1t64:arm64 (0.191-1+b1) ... Setting up libkrb5support0:arm64 (1.20.1-6+b1) ... Setting up tzdata (2024a-4) ... Current default time zone: 'Etc/UTC' Local time is now: Thu May 9 11:53:58 UTC 2024. Universal Time is now: Thu May 9 11:53:58 UTC 2024. Run 'dpkg-reconfigure tzdata' if you wish to change it. Setting up libpgm-5.3-0t64:arm64 (5.3.128~dfsg-2.1) ... Setting up autotools-dev (20220109.1) ... Setting up libcares2:arm64 (1.28.1-1) ... Setting up autopoint (0.21-14) ... Setting up libk5crypto3:arm64 (1.20.1-6+b1) ... Setting up autoconf (2.71-3) ... Setting up dwz (0.15-1+b1) ... Setting up sensible-utils (0.0.22) ... Setting up libuchardet0:arm64 (0.0.8-1+b1) ... Setting up libsub-override-perl (0.10-1) ... Setting up netbase (6.4) ... Setting up libkrb5-3:arm64 (1.20.1-6+b1) ... Setting up libjs-jquery (3.6.1+dfsg+~3.5.14-1) ... Setting up openssl (3.2.1-3) ... Setting up libbsd0:arm64 (0.12.2-1) ... Setting up readline-common (8.2-4) ... Setting up libxml2:arm64 (2.9.14+dfsg-1.3+b3) ... Setting up fonts-font-awesome (5.0.10+really4.7.0~dfsg-4.1) ... Setting up sphinx-rtd-theme-common (2.0.0+dfsg-1) ... Setting up libjs-underscore (1.13.4~dfsg+~1.11.4-3) ... Setting up automake (1:1.16.5-1.3) ... update-alternatives: using /usr/bin/automake-1.16 to provide /usr/bin/automake (automake) in auto mode Setting up libfile-stripnondeterminism-perl (1.13.1-1) ... Setting up python3.12-minimal (3.12.3-1) ... Setting up gettext (0.21-14+b1) ... Setting up libtool (2.4.7-7) ... Setting up intltool-debian (0.35.0+20060710.6) ... Setting up dh-autoreconf (20) ... Setting up ca-certificates (20240203) ... Updating certificates in /etc/ssl/certs... 146 added, 0 removed; done. Setting up libgssapi-krb5-2:arm64 (1.20.1-6+b1) ... Setting up libjs-sphinxdoc (7.2.6-6) ... Setting up libreadline8t64:arm64 (8.2-4) ... Setting up dh-strip-nondeterminism (1.13.1-1) ... Setting up groff-base (1.23.0-4) ... Setting up libxslt1.1:arm64 (1.1.35-1+b1) ... Setting up libzmq5:arm64 (4.3.5-1+b2) ... Setting up libpython3.12-stdlib:arm64 (3.12.3-1) ... Setting up po-debconf (1.0.21+nmu1) ... Setting up libpython3.11-stdlib:arm64 (3.11.9-1) ... Setting up python3.12 (3.12.3-1) ... Setting up man-db (2.12.1-1) ... Not building database; man-db/auto-update is not 'true'. Setting up libpython3-stdlib:arm64 (3.11.8-1) ... Setting up python3.11 (3.11.9-1) ... Setting up debhelper (13.15.3) ... Setting up python3 (3.11.8-1) ... Setting up python3-roundrobin (0.0.4-3) ... Setting up python3-markupsafe (2.1.5-1) ... Setting up python3-wheel (0.43.0-1) ... Setting up python3-psutil (5.9.8-2) ... Setting up python3-six (1.16.0-6) ... Setting up python3-decorator (5.1.1-5) ... Setting up python3-jinja2 (3.1.3-1) ... Setting up python3-packaging (24.0-1) ... Setting up python3-pyproject-hooks (1.0.0-2) ... Setting up python3-certifi (2023.11.17-1) ... Setting up python3-werkzeug (3.0.2-1) ... Setting up python3-brotli (1.1.0-2+b3) ... Setting up python3-greenlet (3.0.1-3) ... Setting up python3-idna (3.6-2) ... Setting up python3-typing-extensions (4.10.0-1) ... Setting up python3-toml (0.10.2-1) ... Setting up python3-installer (0.7.0+dfsg1-3) ... Setting up python3-urllib3 (1.26.18-2) ... Setting up python3-pluggy (1.5.0-1) ... Setting up python3-lxml:arm64 (5.1.0-1) ... Setting up python3-msgpack (1.0.3-3+b1) ... Setting up python3-build (1.2.1-1) ... Setting up python3-cssselect (1.2.0-4) ... Setting up python3-lib2to3 (3.12.3-1) ... Setting up python3-cffi-backend:arm64 (1.16.0-2+b2) ... Setting up python3-webob (1:1.8.7-1) ... Setting up python3-blinker (1.8.1-1) ... Setting up python3-pkg-resources (68.1.2-2) ... Setting up python3-distutils (3.12.3-1) ... python3.12: can't get files for byte-compilation Setting up python3-configargparse (1.7-1) ... Setting up python3-iniconfig (1.1.1-2) ... Setting up python3-setuptools (68.1.2-2) ... Setting up python3-py (1.11.0-2) ... Setting up python3-colorama (0.4.6-4) ... Setting up python3-zope.event (5.0-0.1) ... Setting up python3-zope.interface (6.1-1) ... Setting up python3-pyquery (1.4.3-1) ... Setting up python3-charset-normalizer (3.3.2-1) ... Setting up python3-pytest (7.4.4-3) ... Setting up python3-itsdangerous (2.1.2-4) ... Setting up python3-all (3.11.8-1) ... Setting up python3-gevent (24.2.1-0.1+b1) ... Setting up python3-click (8.1.7-1) ... Setting up python3-chardet (5.2.0+dfsg-1) ... Setting up python3-zmq (24.0.1-5+b1) ... Setting up python3-cryptography (42.0.5-2) ... Setting up python3-requests (2.31.0+dfsg-1) ... Setting up python3-retry (0.9.2-2) ... Setting up python3-geventhttpclient (2.0.11-2) ... Setting up dh-python (6.20240422) ... Setting up pybuild-plugin-pyproject (6.20240422) ... Setting up python3-flask (3.0.3-1) ... Setting up python3-flask-cors (4.0.0-1) ... Setting up python3-flask-login (0.6.3-2) ... Processing triggers for libc-bin (2.38-7) ... Processing triggers for ca-certificates (20240203) ... Updating certificates in /etc/ssl/certs... 0 added, 0 removed; done. Running hooks in /etc/ca-certificates/update.d... done. Reading package lists... Building dependency tree... Reading state information... Reading extended state information... Initializing package states... Writing extended state information... Building tag database... -> Finished parsing the build-deps Reading package lists... Building dependency tree... Reading state information... fakeroot is already the newest version (1.33-1). 0 upgraded, 0 newly installed, 0 to remove and 0 not upgraded. I: Building the package I: user script /srv/workspace/pbuilder/227080/tmp/hooks/A99_set_merged_usr starting Not re-configuring usrmerge for trixie I: user script /srv/workspace/pbuilder/227080/tmp/hooks/A99_set_merged_usr finished hostname: Name or service not known I: Running cd /build/reproducible-path/locust-2.24.0/ && env PATH="/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/i/capture/the/path" HOME="/nonexistent/second-build" dpkg-buildpackage -us -uc -b && env PATH="/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/i/capture/the/path" HOME="/nonexistent/second-build" dpkg-genchanges -S > ../locust_2.24.0-1_source.changes dpkg-buildpackage: info: source package locust dpkg-buildpackage: info: source version 2.24.0-1 dpkg-buildpackage: info: source distribution unstable dpkg-buildpackage: info: source changed by Sandro Tosi dpkg-source --before-build . dpkg-buildpackage: info: host architecture arm64 dpkg-source: info: using options from locust-2.24.0/debian/source/options: --extend-diff-ignore=^[^/]+.egg-info/ fakeroot debian/rules clean dh clean --with python3 --buildsystem=pybuild dh_auto_clean -O--buildsystem=pybuild dh_autoreconf_clean -O--buildsystem=pybuild debian/rules override_dh_clean make[1]: Entering directory '/build/reproducible-path/locust-2.24.0' rm -f locust/_version.py dh_clean make[1]: Leaving directory '/build/reproducible-path/locust-2.24.0' debian/rules build dh build --with python3 --buildsystem=pybuild dh_update_autotools_config -O--buildsystem=pybuild dh_autoreconf -O--buildsystem=pybuild dh_auto_configure -O--buildsystem=pybuild debian/rules execute_before_dh_auto_build make[1]: Entering directory '/build/reproducible-path/locust-2.24.0' echo "version = ''" > locust/_version.py make[1]: Leaving directory '/build/reproducible-path/locust-2.24.0' dh_auto_build -O--buildsystem=pybuild I: pybuild plugin_pyproject:129: Building wheel for python3.12 with "build" module I: pybuild base:311: python3.12 -m build --skip-dependency-check --no-isolation --wheel --outdir /build/reproducible-path/locust-2.24.0/.pybuild/cpython3_3.12_locust * Building wheel... running bdist_wheel running build running build_py creating build creating build/lib creating build/lib/locust copying locust/_version.py -> build/lib/locust copying locust/web.py -> build/lib/locust copying locust/stats.py -> build/lib/locust copying locust/shape.py -> build/lib/locust copying locust/runners.py -> build/lib/locust copying locust/main.py -> build/lib/locust copying locust/log.py -> build/lib/locust copying locust/input_events.py -> build/lib/locust copying locust/html.py -> build/lib/locust copying locust/exception.py -> build/lib/locust copying locust/event.py -> build/lib/locust copying locust/env.py -> build/lib/locust copying locust/dispatch.py -> build/lib/locust copying locust/debug.py -> build/lib/locust copying locust/clients.py -> build/lib/locust copying locust/argument_parser.py -> build/lib/locust copying locust/__main__.py -> build/lib/locust copying locust/__init__.py -> build/lib/locust creating build/lib/locust/util copying locust/util/timespan.py -> build/lib/locust/util copying locust/util/rounding.py -> build/lib/locust/util copying locust/util/load_locustfile.py -> build/lib/locust/util copying locust/util/exception_handler.py -> build/lib/locust/util copying locust/util/deprecation.py -> build/lib/locust/util copying locust/util/cache.py -> build/lib/locust/util copying locust/util/__init__.py -> build/lib/locust/util creating build/lib/locust/user copying locust/user/wait_time.py -> build/lib/locust/user copying locust/user/users.py -> build/lib/locust/user copying locust/user/task.py -> build/lib/locust/user copying locust/user/sequential_taskset.py -> build/lib/locust/user copying locust/user/inspectuser.py -> build/lib/locust/user copying locust/user/__init__.py -> build/lib/locust/user creating build/lib/locust/test copying locust/test/util.py -> build/lib/locust/test copying locust/test/testcases.py -> build/lib/locust/test copying locust/test/test_zmqrpc.py -> build/lib/locust/test copying locust/test/test_web.py -> build/lib/locust/test copying locust/test/test_wait_time.py -> build/lib/locust/test copying locust/test/test_util.py -> build/lib/locust/test copying locust/test/test_users.py -> build/lib/locust/test copying locust/test/test_taskratio.py -> build/lib/locust/test copying locust/test/test_tags.py -> build/lib/locust/test copying locust/test/test_stats.py -> build/lib/locust/test copying locust/test/test_sequential_taskset.py -> build/lib/locust/test copying locust/test/test_runners.py -> build/lib/locust/test copying locust/test/test_parser.py -> build/lib/locust/test copying locust/test/test_old_wait_api.py -> build/lib/locust/test copying locust/test/test_main.py -> build/lib/locust/test copying locust/test/test_log.py -> build/lib/locust/test copying locust/test/test_locust_class.py -> build/lib/locust/test copying locust/test/test_load_locustfile.py -> build/lib/locust/test copying locust/test/test_interruptable_task.py -> build/lib/locust/test copying locust/test/test_http.py -> build/lib/locust/test copying locust/test/test_fasthttp.py -> build/lib/locust/test copying locust/test/test_env.py -> build/lib/locust/test copying locust/test/test_dispatch.py -> build/lib/locust/test copying locust/test/test_debugging.py -> build/lib/locust/test copying locust/test/mock_logging.py -> build/lib/locust/test copying locust/test/mock_locustfile.py -> build/lib/locust/test copying locust/test/fake_module2_for_env_test.py -> build/lib/locust/test copying locust/test/fake_module1_for_env_test.py -> build/lib/locust/test copying locust/test/__init__.py -> build/lib/locust/test creating build/lib/locust/rpc copying locust/rpc/zmqrpc.py -> build/lib/locust/rpc copying locust/rpc/protocol.py -> build/lib/locust/rpc copying locust/rpc/__init__.py -> build/lib/locust/rpc creating build/lib/locust/contrib copying locust/contrib/fasthttp.py -> build/lib/locust/contrib copying locust/contrib/__init__.py -> build/lib/locust/contrib copying locust/py.typed -> build/lib/locust creating build/lib/locust/templates copying locust/templates/stats_data.html -> build/lib/locust/templates copying locust/templates/report.html -> build/lib/locust/templates copying locust/templates/index.html -> build/lib/locust/templates creating build/lib/locust/static copying locust/static/vintage.js -> build/lib/locust/static copying locust/static/tasks.js -> build/lib/locust/static copying locust/static/locust.js -> build/lib/locust/static copying locust/static/jquery.tools.min.js -> build/lib/locust/static copying locust/static/jquery.jqote2.min.js -> build/lib/locust/static copying locust/static/jquery-1.11.3.min.js -> build/lib/locust/static copying locust/static/echarts.common.min.js -> build/lib/locust/static copying locust/static/chart.js -> build/lib/locust/static creating build/lib/locust/static/sass copying locust/static/sass/tables.sass -> build/lib/locust/static/sass copying locust/static/sass/application.sass -> build/lib/locust/static/sass copying locust/static/sass/_mixins.sass -> build/lib/locust/static/sass copying locust/static/sass/_base.sass -> build/lib/locust/static/sass creating build/lib/locust/static/img copying locust/static/img/ui-screenshot-workers.png -> build/lib/locust/static/img copying locust/static/img/ui-screenshot-stats.png -> build/lib/locust/static/img copying locust/static/img/ui-screenshot-start-test.png -> build/lib/locust/static/img copying locust/static/img/ui-screenshot-charts.png -> build/lib/locust/static/img copying locust/static/img/logo.png -> build/lib/locust/static/img copying locust/static/img/favicon.ico -> build/lib/locust/static/img creating build/lib/locust/static/css copying locust/static/css/tables.css.map -> build/lib/locust/static/css copying locust/static/css/tables.css -> build/lib/locust/static/css copying locust/static/css/application.css.map -> build/lib/locust/static/css copying locust/static/css/application.css -> build/lib/locust/static/css creating build/lib/locust/webui creating build/lib/locust/webui/dist copying locust/webui/dist/report.html -> build/lib/locust/webui/dist copying locust/webui/dist/index.html -> build/lib/locust/webui/dist copying locust/webui/dist/auth.html -> build/lib/locust/webui/dist creating build/lib/locust/webui/dist/assets copying locust/webui/dist/assets/logo.png -> build/lib/locust/webui/dist/assets copying locust/webui/dist/assets/index-0d6d578a.js -> build/lib/locust/webui/dist/assets copying locust/webui/dist/assets/favicon.ico -> build/lib/locust/webui/dist/assets installing to build/bdist.linux-aarch64/wheel running install running install_lib creating build/bdist.linux-aarch64 creating build/bdist.linux-aarch64/wheel creating build/bdist.linux-aarch64/wheel/locust creating build/bdist.linux-aarch64/wheel/locust/webui creating build/bdist.linux-aarch64/wheel/locust/webui/dist creating build/bdist.linux-aarch64/wheel/locust/webui/dist/assets copying build/lib/locust/webui/dist/assets/favicon.ico -> build/bdist.linux-aarch64/wheel/locust/webui/dist/assets copying build/lib/locust/webui/dist/assets/index-0d6d578a.js -> build/bdist.linux-aarch64/wheel/locust/webui/dist/assets copying build/lib/locust/webui/dist/assets/logo.png -> build/bdist.linux-aarch64/wheel/locust/webui/dist/assets copying build/lib/locust/webui/dist/auth.html -> build/bdist.linux-aarch64/wheel/locust/webui/dist copying build/lib/locust/webui/dist/index.html -> build/bdist.linux-aarch64/wheel/locust/webui/dist copying build/lib/locust/webui/dist/report.html -> build/bdist.linux-aarch64/wheel/locust/webui/dist creating build/bdist.linux-aarch64/wheel/locust/static creating build/bdist.linux-aarch64/wheel/locust/static/css copying build/lib/locust/static/css/application.css -> build/bdist.linux-aarch64/wheel/locust/static/css copying build/lib/locust/static/css/application.css.map -> build/bdist.linux-aarch64/wheel/locust/static/css copying build/lib/locust/static/css/tables.css -> build/bdist.linux-aarch64/wheel/locust/static/css copying build/lib/locust/static/css/tables.css.map -> build/bdist.linux-aarch64/wheel/locust/static/css creating build/bdist.linux-aarch64/wheel/locust/static/img copying build/lib/locust/static/img/favicon.ico -> build/bdist.linux-aarch64/wheel/locust/static/img copying build/lib/locust/static/img/logo.png -> build/bdist.linux-aarch64/wheel/locust/static/img copying build/lib/locust/static/img/ui-screenshot-charts.png -> build/bdist.linux-aarch64/wheel/locust/static/img copying build/lib/locust/static/img/ui-screenshot-start-test.png -> build/bdist.linux-aarch64/wheel/locust/static/img copying build/lib/locust/static/img/ui-screenshot-stats.png -> build/bdist.linux-aarch64/wheel/locust/static/img copying build/lib/locust/static/img/ui-screenshot-workers.png -> build/bdist.linux-aarch64/wheel/locust/static/img creating build/bdist.linux-aarch64/wheel/locust/static/sass copying build/lib/locust/static/sass/_base.sass -> build/bdist.linux-aarch64/wheel/locust/static/sass copying build/lib/locust/static/sass/_mixins.sass -> build/bdist.linux-aarch64/wheel/locust/static/sass copying build/lib/locust/static/sass/application.sass -> build/bdist.linux-aarch64/wheel/locust/static/sass copying build/lib/locust/static/sass/tables.sass -> build/bdist.linux-aarch64/wheel/locust/static/sass copying build/lib/locust/static/chart.js -> build/bdist.linux-aarch64/wheel/locust/static copying build/lib/locust/static/echarts.common.min.js -> build/bdist.linux-aarch64/wheel/locust/static copying build/lib/locust/static/jquery-1.11.3.min.js -> build/bdist.linux-aarch64/wheel/locust/static copying build/lib/locust/static/jquery.jqote2.min.js -> build/bdist.linux-aarch64/wheel/locust/static copying build/lib/locust/static/jquery.tools.min.js -> build/bdist.linux-aarch64/wheel/locust/static copying build/lib/locust/static/locust.js -> build/bdist.linux-aarch64/wheel/locust/static copying build/lib/locust/static/tasks.js -> build/bdist.linux-aarch64/wheel/locust/static copying build/lib/locust/static/vintage.js -> build/bdist.linux-aarch64/wheel/locust/static creating build/bdist.linux-aarch64/wheel/locust/templates copying build/lib/locust/templates/index.html -> build/bdist.linux-aarch64/wheel/locust/templates copying build/lib/locust/templates/report.html -> build/bdist.linux-aarch64/wheel/locust/templates copying build/lib/locust/templates/stats_data.html -> build/bdist.linux-aarch64/wheel/locust/templates copying build/lib/locust/py.typed -> build/bdist.linux-aarch64/wheel/locust creating build/bdist.linux-aarch64/wheel/locust/contrib copying build/lib/locust/contrib/__init__.py -> build/bdist.linux-aarch64/wheel/locust/contrib copying build/lib/locust/contrib/fasthttp.py -> build/bdist.linux-aarch64/wheel/locust/contrib creating build/bdist.linux-aarch64/wheel/locust/rpc copying build/lib/locust/rpc/__init__.py -> build/bdist.linux-aarch64/wheel/locust/rpc copying build/lib/locust/rpc/protocol.py -> build/bdist.linux-aarch64/wheel/locust/rpc copying build/lib/locust/rpc/zmqrpc.py -> build/bdist.linux-aarch64/wheel/locust/rpc creating build/bdist.linux-aarch64/wheel/locust/test copying build/lib/locust/test/__init__.py -> build/bdist.linux-aarch64/wheel/locust/test copying build/lib/locust/test/fake_module1_for_env_test.py -> build/bdist.linux-aarch64/wheel/locust/test copying build/lib/locust/test/fake_module2_for_env_test.py -> build/bdist.linux-aarch64/wheel/locust/test copying build/lib/locust/test/mock_locustfile.py -> build/bdist.linux-aarch64/wheel/locust/test copying build/lib/locust/test/mock_logging.py -> build/bdist.linux-aarch64/wheel/locust/test copying build/lib/locust/test/test_debugging.py -> build/bdist.linux-aarch64/wheel/locust/test copying build/lib/locust/test/test_dispatch.py -> build/bdist.linux-aarch64/wheel/locust/test copying build/lib/locust/test/test_env.py -> build/bdist.linux-aarch64/wheel/locust/test copying build/lib/locust/test/test_fasthttp.py -> build/bdist.linux-aarch64/wheel/locust/test copying build/lib/locust/test/test_http.py -> build/bdist.linux-aarch64/wheel/locust/test copying build/lib/locust/test/test_interruptable_task.py -> build/bdist.linux-aarch64/wheel/locust/test copying build/lib/locust/test/test_load_locustfile.py -> build/bdist.linux-aarch64/wheel/locust/test copying build/lib/locust/test/test_locust_class.py -> build/bdist.linux-aarch64/wheel/locust/test copying build/lib/locust/test/test_log.py -> build/bdist.linux-aarch64/wheel/locust/test copying build/lib/locust/test/test_main.py -> build/bdist.linux-aarch64/wheel/locust/test copying build/lib/locust/test/test_old_wait_api.py -> build/bdist.linux-aarch64/wheel/locust/test copying build/lib/locust/test/test_parser.py -> build/bdist.linux-aarch64/wheel/locust/test copying build/lib/locust/test/test_runners.py -> build/bdist.linux-aarch64/wheel/locust/test copying build/lib/locust/test/test_sequential_taskset.py -> build/bdist.linux-aarch64/wheel/locust/test copying build/lib/locust/test/test_stats.py -> build/bdist.linux-aarch64/wheel/locust/test copying build/lib/locust/test/test_tags.py -> build/bdist.linux-aarch64/wheel/locust/test copying build/lib/locust/test/test_taskratio.py -> build/bdist.linux-aarch64/wheel/locust/test copying build/lib/locust/test/test_users.py -> build/bdist.linux-aarch64/wheel/locust/test copying build/lib/locust/test/test_util.py -> build/bdist.linux-aarch64/wheel/locust/test copying build/lib/locust/test/test_wait_time.py -> build/bdist.linux-aarch64/wheel/locust/test copying build/lib/locust/test/test_web.py -> build/bdist.linux-aarch64/wheel/locust/test copying build/lib/locust/test/test_zmqrpc.py -> build/bdist.linux-aarch64/wheel/locust/test copying build/lib/locust/test/testcases.py -> build/bdist.linux-aarch64/wheel/locust/test copying build/lib/locust/test/util.py -> build/bdist.linux-aarch64/wheel/locust/test creating build/bdist.linux-aarch64/wheel/locust/user copying build/lib/locust/user/__init__.py -> build/bdist.linux-aarch64/wheel/locust/user copying build/lib/locust/user/inspectuser.py -> build/bdist.linux-aarch64/wheel/locust/user copying build/lib/locust/user/sequential_taskset.py -> build/bdist.linux-aarch64/wheel/locust/user copying build/lib/locust/user/task.py -> build/bdist.linux-aarch64/wheel/locust/user copying build/lib/locust/user/users.py -> build/bdist.linux-aarch64/wheel/locust/user copying build/lib/locust/user/wait_time.py -> build/bdist.linux-aarch64/wheel/locust/user creating build/bdist.linux-aarch64/wheel/locust/util copying build/lib/locust/util/__init__.py -> build/bdist.linux-aarch64/wheel/locust/util copying build/lib/locust/util/cache.py -> build/bdist.linux-aarch64/wheel/locust/util copying build/lib/locust/util/deprecation.py -> build/bdist.linux-aarch64/wheel/locust/util copying build/lib/locust/util/exception_handler.py -> build/bdist.linux-aarch64/wheel/locust/util copying build/lib/locust/util/load_locustfile.py -> build/bdist.linux-aarch64/wheel/locust/util copying build/lib/locust/util/rounding.py -> build/bdist.linux-aarch64/wheel/locust/util copying build/lib/locust/util/timespan.py -> build/bdist.linux-aarch64/wheel/locust/util copying build/lib/locust/__init__.py -> build/bdist.linux-aarch64/wheel/locust copying build/lib/locust/__main__.py -> build/bdist.linux-aarch64/wheel/locust copying build/lib/locust/argument_parser.py -> build/bdist.linux-aarch64/wheel/locust copying build/lib/locust/clients.py -> build/bdist.linux-aarch64/wheel/locust copying build/lib/locust/debug.py -> build/bdist.linux-aarch64/wheel/locust copying build/lib/locust/dispatch.py -> build/bdist.linux-aarch64/wheel/locust copying build/lib/locust/env.py -> build/bdist.linux-aarch64/wheel/locust copying build/lib/locust/event.py -> build/bdist.linux-aarch64/wheel/locust copying build/lib/locust/exception.py -> build/bdist.linux-aarch64/wheel/locust copying build/lib/locust/html.py -> build/bdist.linux-aarch64/wheel/locust copying build/lib/locust/input_events.py -> build/bdist.linux-aarch64/wheel/locust copying build/lib/locust/log.py -> build/bdist.linux-aarch64/wheel/locust copying build/lib/locust/main.py -> build/bdist.linux-aarch64/wheel/locust copying build/lib/locust/runners.py -> build/bdist.linux-aarch64/wheel/locust copying build/lib/locust/shape.py -> build/bdist.linux-aarch64/wheel/locust copying build/lib/locust/stats.py -> build/bdist.linux-aarch64/wheel/locust copying build/lib/locust/web.py -> build/bdist.linux-aarch64/wheel/locust copying build/lib/locust/_version.py -> build/bdist.linux-aarch64/wheel/locust running install_egg_info running egg_info creating locust.egg-info writing locust.egg-info/PKG-INFO writing dependency_links to locust.egg-info/dependency_links.txt writing entry points to locust.egg-info/entry_points.txt writing requirements to locust.egg-info/requires.txt writing top-level names to locust.egg-info/top_level.txt writing manifest file 'locust.egg-info/SOURCES.txt' reading manifest file 'locust.egg-info/SOURCES.txt' reading manifest template 'MANIFEST.in' adding license file 'LICENSE' writing manifest file 'locust.egg-info/SOURCES.txt' Copying locust.egg-info to build/bdist.linux-aarch64/wheel/locust-0.0.0.egg-info running install_scripts creating build/bdist.linux-aarch64/wheel/locust-0.0.0.dist-info/WHEEL creating '/build/reproducible-path/locust-2.24.0/.pybuild/cpython3_3.12_locust/.tmp-35xhnwr8/locust-0.0.0-py3-none-any.whl' and adding 'build/bdist.linux-aarch64/wheel' to it adding 'locust/__init__.py' adding 'locust/__main__.py' adding 'locust/_version.py' adding 'locust/argument_parser.py' adding 'locust/clients.py' adding 'locust/debug.py' adding 'locust/dispatch.py' adding 'locust/env.py' adding 'locust/event.py' adding 'locust/exception.py' adding 'locust/html.py' adding 'locust/input_events.py' adding 'locust/log.py' adding 'locust/main.py' adding 'locust/py.typed' adding 'locust/runners.py' adding 'locust/shape.py' adding 'locust/stats.py' adding 'locust/web.py' adding 'locust/contrib/__init__.py' adding 'locust/contrib/fasthttp.py' adding 'locust/rpc/__init__.py' adding 'locust/rpc/protocol.py' adding 'locust/rpc/zmqrpc.py' adding 'locust/static/chart.js' adding 'locust/static/echarts.common.min.js' adding 'locust/static/jquery-1.11.3.min.js' adding 'locust/static/jquery.jqote2.min.js' adding 'locust/static/jquery.tools.min.js' adding 'locust/static/locust.js' adding 'locust/static/tasks.js' adding 'locust/static/vintage.js' adding 'locust/static/css/application.css' adding 'locust/static/css/application.css.map' adding 'locust/static/css/tables.css' adding 'locust/static/css/tables.css.map' adding 'locust/static/img/favicon.ico' adding 'locust/static/img/logo.png' adding 'locust/static/img/ui-screenshot-charts.png' adding 'locust/static/img/ui-screenshot-start-test.png' adding 'locust/static/img/ui-screenshot-stats.png' adding 'locust/static/img/ui-screenshot-workers.png' adding 'locust/static/sass/_base.sass' adding 'locust/static/sass/_mixins.sass' adding 'locust/static/sass/application.sass' adding 'locust/static/sass/tables.sass' adding 'locust/templates/index.html' adding 'locust/templates/report.html' adding 'locust/templates/stats_data.html' adding 'locust/test/__init__.py' adding 'locust/test/fake_module1_for_env_test.py' adding 'locust/test/fake_module2_for_env_test.py' adding 'locust/test/mock_locustfile.py' adding 'locust/test/mock_logging.py' adding 'locust/test/test_debugging.py' adding 'locust/test/test_dispatch.py' adding 'locust/test/test_env.py' adding 'locust/test/test_fasthttp.py' adding 'locust/test/test_http.py' adding 'locust/test/test_interruptable_task.py' adding 'locust/test/test_load_locustfile.py' adding 'locust/test/test_locust_class.py' adding 'locust/test/test_log.py' adding 'locust/test/test_main.py' adding 'locust/test/test_old_wait_api.py' adding 'locust/test/test_parser.py' adding 'locust/test/test_runners.py' adding 'locust/test/test_sequential_taskset.py' adding 'locust/test/test_stats.py' adding 'locust/test/test_tags.py' adding 'locust/test/test_taskratio.py' adding 'locust/test/test_users.py' adding 'locust/test/test_util.py' adding 'locust/test/test_wait_time.py' adding 'locust/test/test_web.py' adding 'locust/test/test_zmqrpc.py' adding 'locust/test/testcases.py' adding 'locust/test/util.py' adding 'locust/user/__init__.py' adding 'locust/user/inspectuser.py' adding 'locust/user/sequential_taskset.py' adding 'locust/user/task.py' adding 'locust/user/users.py' adding 'locust/user/wait_time.py' adding 'locust/util/__init__.py' adding 'locust/util/cache.py' adding 'locust/util/deprecation.py' adding 'locust/util/exception_handler.py' adding 'locust/util/load_locustfile.py' adding 'locust/util/rounding.py' adding 'locust/util/timespan.py' adding 'locust/webui/dist/auth.html' adding 'locust/webui/dist/index.html' adding 'locust/webui/dist/report.html' adding 'locust/webui/dist/assets/favicon.ico' adding 'locust/webui/dist/assets/index-0d6d578a.js' adding 'locust/webui/dist/assets/logo.png' adding 'locust-0.0.0.dist-info/LICENSE' adding 'locust-0.0.0.dist-info/METADATA' adding 'locust-0.0.0.dist-info/WHEEL' adding 'locust-0.0.0.dist-info/entry_points.txt' adding 'locust-0.0.0.dist-info/top_level.txt' adding 'locust-0.0.0.dist-info/RECORD' removing build/bdist.linux-aarch64/wheel Successfully built locust-0.0.0-py3-none-any.whl I: pybuild plugin_pyproject:144: Unpacking wheel built for python3.12 with "installer" module I: pybuild plugin_pyproject:129: Building wheel for python3.11 with "build" module I: pybuild base:311: python3.11 -m build --skip-dependency-check --no-isolation --wheel --outdir /build/reproducible-path/locust-2.24.0/.pybuild/cpython3_3.11_locust * Building wheel... running bdist_wheel running build running build_py installing to build/bdist.linux-aarch64/wheel running install running install_lib creating build/bdist.linux-aarch64/wheel creating build/bdist.linux-aarch64/wheel/locust creating build/bdist.linux-aarch64/wheel/locust/webui creating build/bdist.linux-aarch64/wheel/locust/webui/dist creating build/bdist.linux-aarch64/wheel/locust/webui/dist/assets copying build/lib/locust/webui/dist/assets/favicon.ico -> build/bdist.linux-aarch64/wheel/locust/webui/dist/assets copying build/lib/locust/webui/dist/assets/index-0d6d578a.js -> build/bdist.linux-aarch64/wheel/locust/webui/dist/assets copying build/lib/locust/webui/dist/assets/logo.png -> build/bdist.linux-aarch64/wheel/locust/webui/dist/assets copying build/lib/locust/webui/dist/auth.html -> build/bdist.linux-aarch64/wheel/locust/webui/dist copying build/lib/locust/webui/dist/index.html -> build/bdist.linux-aarch64/wheel/locust/webui/dist copying build/lib/locust/webui/dist/report.html -> build/bdist.linux-aarch64/wheel/locust/webui/dist creating build/bdist.linux-aarch64/wheel/locust/static creating build/bdist.linux-aarch64/wheel/locust/static/css copying build/lib/locust/static/css/application.css -> build/bdist.linux-aarch64/wheel/locust/static/css copying build/lib/locust/static/css/application.css.map -> build/bdist.linux-aarch64/wheel/locust/static/css copying build/lib/locust/static/css/tables.css -> build/bdist.linux-aarch64/wheel/locust/static/css copying build/lib/locust/static/css/tables.css.map -> build/bdist.linux-aarch64/wheel/locust/static/css creating build/bdist.linux-aarch64/wheel/locust/static/img copying build/lib/locust/static/img/favicon.ico -> build/bdist.linux-aarch64/wheel/locust/static/img copying build/lib/locust/static/img/logo.png -> build/bdist.linux-aarch64/wheel/locust/static/img copying build/lib/locust/static/img/ui-screenshot-charts.png -> build/bdist.linux-aarch64/wheel/locust/static/img copying build/lib/locust/static/img/ui-screenshot-start-test.png -> build/bdist.linux-aarch64/wheel/locust/static/img copying build/lib/locust/static/img/ui-screenshot-stats.png -> build/bdist.linux-aarch64/wheel/locust/static/img copying build/lib/locust/static/img/ui-screenshot-workers.png -> build/bdist.linux-aarch64/wheel/locust/static/img creating build/bdist.linux-aarch64/wheel/locust/static/sass copying build/lib/locust/static/sass/_base.sass -> build/bdist.linux-aarch64/wheel/locust/static/sass copying build/lib/locust/static/sass/_mixins.sass -> build/bdist.linux-aarch64/wheel/locust/static/sass copying build/lib/locust/static/sass/application.sass -> build/bdist.linux-aarch64/wheel/locust/static/sass copying build/lib/locust/static/sass/tables.sass -> build/bdist.linux-aarch64/wheel/locust/static/sass copying build/lib/locust/static/chart.js -> build/bdist.linux-aarch64/wheel/locust/static copying build/lib/locust/static/echarts.common.min.js -> build/bdist.linux-aarch64/wheel/locust/static copying build/lib/locust/static/jquery-1.11.3.min.js -> build/bdist.linux-aarch64/wheel/locust/static copying build/lib/locust/static/jquery.jqote2.min.js -> build/bdist.linux-aarch64/wheel/locust/static copying build/lib/locust/static/jquery.tools.min.js -> build/bdist.linux-aarch64/wheel/locust/static copying build/lib/locust/static/locust.js -> build/bdist.linux-aarch64/wheel/locust/static copying build/lib/locust/static/tasks.js -> build/bdist.linux-aarch64/wheel/locust/static copying build/lib/locust/static/vintage.js -> build/bdist.linux-aarch64/wheel/locust/static creating build/bdist.linux-aarch64/wheel/locust/templates copying build/lib/locust/templates/index.html -> build/bdist.linux-aarch64/wheel/locust/templates copying build/lib/locust/templates/report.html -> build/bdist.linux-aarch64/wheel/locust/templates copying build/lib/locust/templates/stats_data.html -> build/bdist.linux-aarch64/wheel/locust/templates copying build/lib/locust/py.typed -> build/bdist.linux-aarch64/wheel/locust creating build/bdist.linux-aarch64/wheel/locust/contrib copying build/lib/locust/contrib/__init__.py -> build/bdist.linux-aarch64/wheel/locust/contrib copying build/lib/locust/contrib/fasthttp.py -> build/bdist.linux-aarch64/wheel/locust/contrib creating build/bdist.linux-aarch64/wheel/locust/rpc copying build/lib/locust/rpc/__init__.py -> build/bdist.linux-aarch64/wheel/locust/rpc copying build/lib/locust/rpc/protocol.py -> build/bdist.linux-aarch64/wheel/locust/rpc copying build/lib/locust/rpc/zmqrpc.py -> build/bdist.linux-aarch64/wheel/locust/rpc creating build/bdist.linux-aarch64/wheel/locust/test copying build/lib/locust/test/__init__.py -> build/bdist.linux-aarch64/wheel/locust/test copying build/lib/locust/test/fake_module1_for_env_test.py -> build/bdist.linux-aarch64/wheel/locust/test copying build/lib/locust/test/fake_module2_for_env_test.py -> build/bdist.linux-aarch64/wheel/locust/test copying build/lib/locust/test/mock_locustfile.py -> build/bdist.linux-aarch64/wheel/locust/test copying build/lib/locust/test/mock_logging.py -> build/bdist.linux-aarch64/wheel/locust/test copying build/lib/locust/test/test_debugging.py -> build/bdist.linux-aarch64/wheel/locust/test copying build/lib/locust/test/test_dispatch.py -> build/bdist.linux-aarch64/wheel/locust/test copying build/lib/locust/test/test_env.py -> build/bdist.linux-aarch64/wheel/locust/test copying build/lib/locust/test/test_fasthttp.py -> build/bdist.linux-aarch64/wheel/locust/test copying build/lib/locust/test/test_http.py -> build/bdist.linux-aarch64/wheel/locust/test copying build/lib/locust/test/test_interruptable_task.py -> build/bdist.linux-aarch64/wheel/locust/test copying build/lib/locust/test/test_load_locustfile.py -> build/bdist.linux-aarch64/wheel/locust/test copying build/lib/locust/test/test_locust_class.py -> build/bdist.linux-aarch64/wheel/locust/test copying build/lib/locust/test/test_log.py -> build/bdist.linux-aarch64/wheel/locust/test copying build/lib/locust/test/test_main.py -> build/bdist.linux-aarch64/wheel/locust/test copying build/lib/locust/test/test_old_wait_api.py -> build/bdist.linux-aarch64/wheel/locust/test copying build/lib/locust/test/test_parser.py -> build/bdist.linux-aarch64/wheel/locust/test copying build/lib/locust/test/test_runners.py -> build/bdist.linux-aarch64/wheel/locust/test copying build/lib/locust/test/test_sequential_taskset.py -> build/bdist.linux-aarch64/wheel/locust/test copying build/lib/locust/test/test_stats.py -> build/bdist.linux-aarch64/wheel/locust/test copying build/lib/locust/test/test_tags.py -> build/bdist.linux-aarch64/wheel/locust/test copying build/lib/locust/test/test_taskratio.py -> build/bdist.linux-aarch64/wheel/locust/test copying build/lib/locust/test/test_users.py -> build/bdist.linux-aarch64/wheel/locust/test copying build/lib/locust/test/test_util.py -> build/bdist.linux-aarch64/wheel/locust/test copying build/lib/locust/test/test_wait_time.py -> build/bdist.linux-aarch64/wheel/locust/test copying build/lib/locust/test/test_web.py -> build/bdist.linux-aarch64/wheel/locust/test copying build/lib/locust/test/test_zmqrpc.py -> build/bdist.linux-aarch64/wheel/locust/test copying build/lib/locust/test/testcases.py -> build/bdist.linux-aarch64/wheel/locust/test copying build/lib/locust/test/util.py -> build/bdist.linux-aarch64/wheel/locust/test creating build/bdist.linux-aarch64/wheel/locust/user copying build/lib/locust/user/__init__.py -> build/bdist.linux-aarch64/wheel/locust/user copying build/lib/locust/user/inspectuser.py -> build/bdist.linux-aarch64/wheel/locust/user copying build/lib/locust/user/sequential_taskset.py -> build/bdist.linux-aarch64/wheel/locust/user copying build/lib/locust/user/task.py -> build/bdist.linux-aarch64/wheel/locust/user copying build/lib/locust/user/users.py -> build/bdist.linux-aarch64/wheel/locust/user copying build/lib/locust/user/wait_time.py -> build/bdist.linux-aarch64/wheel/locust/user creating build/bdist.linux-aarch64/wheel/locust/util copying build/lib/locust/util/__init__.py -> build/bdist.linux-aarch64/wheel/locust/util copying build/lib/locust/util/cache.py -> build/bdist.linux-aarch64/wheel/locust/util copying build/lib/locust/util/deprecation.py -> build/bdist.linux-aarch64/wheel/locust/util copying build/lib/locust/util/exception_handler.py -> build/bdist.linux-aarch64/wheel/locust/util copying build/lib/locust/util/load_locustfile.py -> build/bdist.linux-aarch64/wheel/locust/util copying build/lib/locust/util/rounding.py -> build/bdist.linux-aarch64/wheel/locust/util copying build/lib/locust/util/timespan.py -> build/bdist.linux-aarch64/wheel/locust/util copying build/lib/locust/__init__.py -> build/bdist.linux-aarch64/wheel/locust copying build/lib/locust/__main__.py -> build/bdist.linux-aarch64/wheel/locust copying build/lib/locust/argument_parser.py -> build/bdist.linux-aarch64/wheel/locust copying build/lib/locust/clients.py -> build/bdist.linux-aarch64/wheel/locust copying build/lib/locust/debug.py -> build/bdist.linux-aarch64/wheel/locust copying build/lib/locust/dispatch.py -> build/bdist.linux-aarch64/wheel/locust copying build/lib/locust/env.py -> build/bdist.linux-aarch64/wheel/locust copying build/lib/locust/event.py -> build/bdist.linux-aarch64/wheel/locust copying build/lib/locust/exception.py -> build/bdist.linux-aarch64/wheel/locust copying build/lib/locust/html.py -> build/bdist.linux-aarch64/wheel/locust copying build/lib/locust/input_events.py -> build/bdist.linux-aarch64/wheel/locust copying build/lib/locust/log.py -> build/bdist.linux-aarch64/wheel/locust copying build/lib/locust/main.py -> build/bdist.linux-aarch64/wheel/locust copying build/lib/locust/runners.py -> build/bdist.linux-aarch64/wheel/locust copying build/lib/locust/shape.py -> build/bdist.linux-aarch64/wheel/locust copying build/lib/locust/stats.py -> build/bdist.linux-aarch64/wheel/locust copying build/lib/locust/web.py -> build/bdist.linux-aarch64/wheel/locust copying build/lib/locust/_version.py -> build/bdist.linux-aarch64/wheel/locust running install_egg_info running egg_info writing locust.egg-info/PKG-INFO writing dependency_links to locust.egg-info/dependency_links.txt writing entry points to locust.egg-info/entry_points.txt writing requirements to locust.egg-info/requires.txt writing top-level names to locust.egg-info/top_level.txt reading manifest file 'locust.egg-info/SOURCES.txt' reading manifest template 'MANIFEST.in' adding license file 'LICENSE' writing manifest file 'locust.egg-info/SOURCES.txt' Copying locust.egg-info to build/bdist.linux-aarch64/wheel/locust-0.0.0.egg-info running install_scripts creating build/bdist.linux-aarch64/wheel/locust-0.0.0.dist-info/WHEEL creating '/build/reproducible-path/locust-2.24.0/.pybuild/cpython3_3.11_locust/.tmp-fchhrscb/locust-0.0.0-py3-none-any.whl' and adding 'build/bdist.linux-aarch64/wheel' to it adding 'locust/__init__.py' adding 'locust/__main__.py' adding 'locust/_version.py' adding 'locust/argument_parser.py' adding 'locust/clients.py' adding 'locust/debug.py' adding 'locust/dispatch.py' adding 'locust/env.py' adding 'locust/event.py' adding 'locust/exception.py' adding 'locust/html.py' adding 'locust/input_events.py' adding 'locust/log.py' adding 'locust/main.py' adding 'locust/py.typed' adding 'locust/runners.py' adding 'locust/shape.py' adding 'locust/stats.py' adding 'locust/web.py' adding 'locust/contrib/__init__.py' adding 'locust/contrib/fasthttp.py' adding 'locust/rpc/__init__.py' adding 'locust/rpc/protocol.py' adding 'locust/rpc/zmqrpc.py' adding 'locust/static/chart.js' adding 'locust/static/echarts.common.min.js' adding 'locust/static/jquery-1.11.3.min.js' adding 'locust/static/jquery.jqote2.min.js' adding 'locust/static/jquery.tools.min.js' adding 'locust/static/locust.js' adding 'locust/static/tasks.js' adding 'locust/static/vintage.js' adding 'locust/static/css/application.css' adding 'locust/static/css/application.css.map' adding 'locust/static/css/tables.css' adding 'locust/static/css/tables.css.map' adding 'locust/static/img/favicon.ico' adding 'locust/static/img/logo.png' adding 'locust/static/img/ui-screenshot-charts.png' adding 'locust/static/img/ui-screenshot-start-test.png' adding 'locust/static/img/ui-screenshot-stats.png' adding 'locust/static/img/ui-screenshot-workers.png' adding 'locust/static/sass/_base.sass' adding 'locust/static/sass/_mixins.sass' adding 'locust/static/sass/application.sass' adding 'locust/static/sass/tables.sass' adding 'locust/templates/index.html' adding 'locust/templates/report.html' adding 'locust/templates/stats_data.html' adding 'locust/test/__init__.py' adding 'locust/test/fake_module1_for_env_test.py' adding 'locust/test/fake_module2_for_env_test.py' adding 'locust/test/mock_locustfile.py' adding 'locust/test/mock_logging.py' adding 'locust/test/test_debugging.py' adding 'locust/test/test_dispatch.py' adding 'locust/test/test_env.py' adding 'locust/test/test_fasthttp.py' adding 'locust/test/test_http.py' adding 'locust/test/test_interruptable_task.py' adding 'locust/test/test_load_locustfile.py' adding 'locust/test/test_locust_class.py' adding 'locust/test/test_log.py' adding 'locust/test/test_main.py' adding 'locust/test/test_old_wait_api.py' adding 'locust/test/test_parser.py' adding 'locust/test/test_runners.py' adding 'locust/test/test_sequential_taskset.py' adding 'locust/test/test_stats.py' adding 'locust/test/test_tags.py' adding 'locust/test/test_taskratio.py' adding 'locust/test/test_users.py' adding 'locust/test/test_util.py' adding 'locust/test/test_wait_time.py' adding 'locust/test/test_web.py' adding 'locust/test/test_zmqrpc.py' adding 'locust/test/testcases.py' adding 'locust/test/util.py' adding 'locust/user/__init__.py' adding 'locust/user/inspectuser.py' adding 'locust/user/sequential_taskset.py' adding 'locust/user/task.py' adding 'locust/user/users.py' adding 'locust/user/wait_time.py' adding 'locust/util/__init__.py' adding 'locust/util/cache.py' adding 'locust/util/deprecation.py' adding 'locust/util/exception_handler.py' adding 'locust/util/load_locustfile.py' adding 'locust/util/rounding.py' adding 'locust/util/timespan.py' adding 'locust/webui/dist/auth.html' adding 'locust/webui/dist/index.html' adding 'locust/webui/dist/report.html' adding 'locust/webui/dist/assets/favicon.ico' adding 'locust/webui/dist/assets/index-0d6d578a.js' adding 'locust/webui/dist/assets/logo.png' adding 'locust-0.0.0.dist-info/LICENSE' adding 'locust-0.0.0.dist-info/METADATA' adding 'locust-0.0.0.dist-info/WHEEL' adding 'locust-0.0.0.dist-info/entry_points.txt' adding 'locust-0.0.0.dist-info/top_level.txt' adding 'locust-0.0.0.dist-info/RECORD' removing build/bdist.linux-aarch64/wheel Successfully built locust-0.0.0-py3-none-any.whl I: pybuild plugin_pyproject:144: Unpacking wheel built for python3.11 with "installer" module debian/rules override_dh_auto_test make[1]: Entering directory '/build/reproducible-path/locust-2.24.0' # examples/test_data_management.py - attempted network access during pytest collection phase # TestMasterWorkerRunners times out after a long time http_proxy= https_proxy= PATH=/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/i/capture/the/path:/build/reproducible-path/locust-2.24.0/debian PYBUILD_SYSTEM=custom PYBUILD_TEST_ARGS="PYTHONPATH={build_dir} {interpreter} -m pytest -v --ignore=examples/test_data_management.py -k 'not TestMasterWorkerRunners'" dh_auto_test I: pybuild base:311: PYTHONPATH=/build/reproducible-path/locust-2.24.0/.pybuild/cpython3_3.12_locust/build python3.12 -m pytest -v --ignore=examples/test_data_management.py -k 'not TestMasterWorkerRunners' ============================= test session starts ============================== platform linux -- Python 3.12.3, pytest-7.4.4, pluggy-1.5.0 -- /usr/bin/python3.12 cachedir: .pytest_cache rootdir: /build/reproducible-path/locust-2.24.0 collecting ... collected 564 items / 15 deselected / 549 selected locust/test/test_debugging.py::TestDebugging::test_run_single_user_pass_host_to_user_classes PASSED [ 0%] locust/test/test_dispatch.py::TestRampUpUsersFromZero::test_ramp_up_users_to_3_workers_with_spawn_rate_of_0_5 PASSED [ 0%] locust/test/test_dispatch.py::TestRampUpUsersFromZero::test_ramp_up_users_to_3_workers_with_spawn_rate_of_1 PASSED [ 0%] locust/test/test_dispatch.py::TestRampUpUsersFromZero::test_ramp_up_users_to_3_workers_with_spawn_rate_of_2 PASSED [ 0%] locust/test/test_dispatch.py::TestRampUpUsersFromZero::test_ramp_up_users_to_3_workers_with_spawn_rate_of_2_4 PASSED [ 0%] locust/test/test_dispatch.py::TestRampUpUsersFromZero::test_ramp_up_users_to_3_workers_with_spawn_rate_of_3 PASSED [ 1%] locust/test/test_dispatch.py::TestRampUpUsersFromZero::test_ramp_up_users_to_3_workers_with_spawn_rate_of_4 PASSED [ 1%] locust/test/test_dispatch.py::TestRampUpUsersFromZero::test_ramp_up_users_to_3_workers_with_spawn_rate_of_9 PASSED [ 1%] locust/test/test_dispatch.py::TestRampUpUsersFromZero::test_ramp_up_users_to_4_workers_with_spawn_rate_of_1 PASSED [ 1%] locust/test/test_dispatch.py::TestRampUpUsersFromZero::test_users_are_distributed_evenly_across_hosts PASSED [ 1%] locust/test/test_dispatch.py::TestWaitBetweenDispatch::test_wait_between_dispatch PASSED [ 2%] locust/test/test_dispatch.py::TestRampDownUsersToZero::test_ramp_down_users_to_3_workers_with_spawn_rate_of_0_5 PASSED [ 2%] locust/test/test_dispatch.py::TestRampDownUsersToZero::test_ramp_down_users_to_3_workers_with_spawn_rate_of_1 PASSED [ 2%] locust/test/test_dispatch.py::TestRampDownUsersToZero::test_ramp_down_users_to_3_workers_with_spawn_rate_of_2 PASSED [ 2%] locust/test/test_dispatch.py::TestRampDownUsersToZero::test_ramp_down_users_to_3_workers_with_spawn_rate_of_2_4 PASSED [ 2%] locust/test/test_dispatch.py::TestRampDownUsersToZero::test_ramp_down_users_to_3_workers_with_spawn_rate_of_3 PASSED [ 2%] locust/test/test_dispatch.py::TestRampDownUsersToZero::test_ramp_down_users_to_3_workers_with_spawn_rate_of_4 PASSED [ 3%] locust/test/test_dispatch.py::TestRampDownUsersToZero::test_ramp_down_users_to_3_workers_with_spawn_rate_of_9 PASSED [ 3%] locust/test/test_dispatch.py::TestRampDownUsersToZero::test_ramp_down_users_to_4_workers_with_spawn_rate_of_1 PASSED [ 3%] locust/test/test_dispatch.py::TestRampUpThenDownThenUp::test_ramp_up_then_down_then_up SKIPPED [ 3%] locust/test/test_dispatch.py::TestDispatchUsersToWorkersHavingTheSameUsersAsTheTarget::test_dispatch_users_to_3_workers PASSED [ 3%] locust/test/test_dispatch.py::TestDistributionIsRespectedDuringDispatch::test_dispatch_75_users_to_4_workers_with_spawn_rate_of_5 PASSED [ 4%] locust/test/test_dispatch.py::TestLargeScale::test_distribute_users PASSED [ 4%] locust/test/test_dispatch.py::TestLargeScale::test_ramp_down_from_100_000_to_0_users_with_50_user_classes_and_1000_workers_and_5000_spawn_rate PASSED [ 4%] locust/test/test_dispatch.py::TestLargeScale::test_ramp_up_from_0_to_100_000_users_with_50_user_classes_and_1000_workers_and_5000_spawn_rate PASSED [ 4%] locust/test/test_dispatch.py::TestSmallConsecutiveRamping::test_consecutive_ramp_up_and_ramp_down PASSED [ 4%] locust/test/test_dispatch.py::TestRampingMiscellaneous::test_spawn_rate_greater_than_target_user_count PASSED [ 4%] locust/test/test_dispatch.py::TestRemoveWorker::test_remove_last_worker PASSED [ 5%] locust/test/test_dispatch.py::TestRemoveWorker::test_remove_two_workers_between_two_ramp_ups PASSED [ 5%] locust/test/test_dispatch.py::TestRemoveWorker::test_remove_two_workers_during_ramp_down PASSED [ 5%] locust/test/test_dispatch.py::TestRemoveWorker::test_remove_two_workers_during_ramp_up PASSED [ 5%] locust/test/test_dispatch.py::TestRemoveWorker::test_remove_worker_between_two_ramp_ups PASSED [ 5%] locust/test/test_dispatch.py::TestRemoveWorker::test_remove_worker_during_ramp_down PASSED [ 6%] locust/test/test_dispatch.py::TestRemoveWorker::test_remove_worker_during_ramp_up PASSED [ 6%] locust/test/test_dispatch.py::TestRemoveWorker::test_remove_worker_during_ramp_up_with_fixed_user PASSED [ 6%] locust/test/test_dispatch.py::TestAddWorker::test_add_two_workers_between_two_ramp_ups PASSED [ 6%] locust/test/test_dispatch.py::TestAddWorker::test_add_two_workers_during_ramp_down PASSED [ 6%] locust/test/test_dispatch.py::TestAddWorker::test_add_two_workers_during_ramp_up PASSED [ 6%] locust/test/test_dispatch.py::TestAddWorker::test_add_worker_between_two_ramp_ups PASSED [ 7%] locust/test/test_dispatch.py::TestAddWorker::test_add_worker_during_ramp_down PASSED [ 7%] locust/test/test_dispatch.py::TestAddWorker::test_add_worker_during_ramp_up PASSED [ 7%] locust/test/test_dispatch.py::TestAddWorker::test_add_worker_during_ramp_up_with_fixed_user PASSED [ 7%] locust/test/test_dispatch.py::TestRampUpUsersFromZeroWithFixed::test_ramp_up_2_weigted_user_with_1_fixed_user PASSED [ 7%] locust/test/test_dispatch.py::TestRampUpUsersFromZeroWithFixed::test_ramp_up_only_fixed_users PASSED [ 8%] locust/test/test_dispatch.py::TestRampUpUsersFromZeroWithFixed::test_ramp_up_partially_ramp_down_and_rump_up_to_target PASSED [ 8%] locust/test/test_dispatch.py::TestRampUpUsersFromZeroWithFixed::test_ramp_up_ramp_down_and_ramp_up_again PASSED [ 8%] locust/test/test_dispatch.py::TestRampUpUsersFromZeroWithFixed::test_ramp_up_ramp_down_and_ramp_up_again_single_fixed_class PASSED [ 8%] locust/test/test_dispatch.py::TestRampUpUsersFromZeroWithFixed::test_ramp_up_various_count_weigted_and_fixed_users PASSED [ 8%] locust/test/test_dispatch.py::TestRampUpDifferentUsers::test_add_worker_during_ramp_up_custom_classes PASSED [ 8%] locust/test/test_dispatch.py::TestRampUpDifferentUsers::test_ramp_down_custom_user_classes_respect_weighting PASSED [ 9%] locust/test/test_dispatch.py::TestRampUpDifferentUsers::test_ramp_up_different_users_each_dispatch_multiple_worker PASSED [ 9%] locust/test/test_dispatch.py::TestRampUpDifferentUsers::test_ramp_up_different_users_for_each_dispatch PASSED [ 9%] locust/test/test_dispatch.py::TestRampUpDifferentUsers::test_ramp_up_first_half_user1_second_half_user2 PASSED [ 9%] locust/test/test_dispatch.py::TestRampUpDifferentUsers::test_ramp_up_first_one_user_then_all_classes PASSED [ 9%] locust/test/test_dispatch.py::TestRampUpDifferentUsers::test_ramp_up_one_user_class_multiple_worker PASSED [ 10%] locust/test/test_dispatch.py::TestRampUpDifferentUsers::test_ramp_up_only_one_kind_of_user PASSED [ 10%] locust/test/test_dispatch.py::TestRampUpDifferentUsers::test_remove_worker_during_ramp_up_custom_classes PASSED [ 10%] locust/test/test_env.py::TestEnvironment::test_all_user_classes_with_zero_weight_raises_exception PASSED [ 10%] locust/test/test_env.py::TestEnvironment::test_assign_equal_weights PASSED [ 10%] locust/test/test_env.py::TestEnvironment::test_dispatcher_class_attribute PASSED [ 10%] locust/test/test_env.py::TestEnvironment::test_shape_class_attribute PASSED [ 11%] locust/test/test_env.py::TestEnvironment::test_update_user_class PASSED [ 11%] locust/test/test_env.py::TestEnvironment::test_user_classes_count PASSED [ 11%] locust/test/test_env.py::TestEnvironment::test_user_classes_with_same_name_is_error PASSED [ 11%] locust/test/test_env.py::TestEnvironment::test_user_classes_with_zero_weight_are_removed PASSED [ 11%] locust/test/test_fasthttp.py::TestFastHttpSession::test_204 PASSED [ 12%] locust/test/test_fasthttp.py::TestFastHttpSession::test_404 PASSED [ 12%] locust/test/test_fasthttp.py::TestFastHttpSession::test_catch_response_default_fail PASSED [ 12%] locust/test/test_fasthttp.py::TestFastHttpSession::test_catch_response_default_success PASSED [ 12%] locust/test/test_fasthttp.py::TestFastHttpSession::test_catch_response_fail_successful_request PASSED [ 12%] locust/test/test_fasthttp.py::TestFastHttpSession::test_catch_response_multiple_failure_and_success PASSED [ 12%] locust/test/test_fasthttp.py::TestFastHttpSession::test_catch_response_pass_failed_request PASSED [ 13%] locust/test/test_fasthttp.py::TestFastHttpSession::test_catch_response_pass_failed_request_with_other_exception_within_block PASSED [ 13%] locust/test/test_fasthttp.py::TestFastHttpSession::test_connection_error PASSED [ 13%] locust/test/test_fasthttp.py::TestFastHttpSession::test_cookie PASSED [ 13%] locust/test/test_fasthttp.py::TestFastHttpSession::test_custom_ssl_context_fail_with_bad_context PASSED [ 13%] locust/test/test_fasthttp.py::TestFastHttpSession::test_custom_ssl_context_passed_correct_to_client_pool PASSED [ 14%] locust/test/test_fasthttp.py::TestFastHttpSession::test_delete PASSED [ 14%] locust/test/test_fasthttp.py::TestFastHttpSession::test_error_message_with_name_replacement PASSED [ 14%] locust/test/test_fasthttp.py::TestFastHttpSession::test_get PASSED [ 14%] locust/test/test_fasthttp.py::TestFastHttpSession::test_head PASSED [ 14%] locust/test/test_fasthttp.py::TestFastHttpSession::test_json_payload PASSED [ 14%] locust/test/test_fasthttp.py::TestFastHttpSession::test_options PASSED [ 15%] locust/test/test_fasthttp.py::TestFastHttpSession::test_patch PASSED [ 15%] locust/test/test_fasthttp.py::TestFastHttpSession::test_post_redirect PASSED [ 15%] locust/test/test_fasthttp.py::TestFastHttpSession::test_slow_redirect PASSED [ 15%] locust/test/test_fasthttp.py::TestFastHttpSession::test_streaming_response PASSED [ 15%] locust/test/test_fasthttp.py::TestRequestStatsWithWebserver::test_request_connection_error PASSED [ 16%] locust/test/test_fasthttp.py::TestRequestStatsWithWebserver::test_request_stats_content_length PASSED [ 16%] locust/test/test_fasthttp.py::TestRequestStatsWithWebserver::test_request_stats_named_endpoint PASSED [ 16%] locust/test/test_fasthttp.py::TestRequestStatsWithWebserver::test_request_stats_no_content_length PASSED [ 16%] locust/test/test_fasthttp.py::TestRequestStatsWithWebserver::test_request_stats_no_content_length_streaming PASSED [ 16%] locust/test/test_fasthttp.py::TestRequestStatsWithWebserver::test_request_stats_put PASSED [ 16%] locust/test/test_fasthttp.py::TestRequestStatsWithWebserver::test_request_stats_query_variables PASSED [ 17%] locust/test/test_fasthttp.py::TestFastHttpUserClass::test_allow_redirects_override PASSED [ 17%] locust/test/test_fasthttp.py::TestFastHttpUserClass::test_class_context PASSED [ 17%] locust/test/test_fasthttp.py::TestFastHttpUserClass::test_client_basic_auth PASSED [ 17%] locust/test/test_fasthttp.py::TestFastHttpUserClass::test_client_delete PASSED [ 17%] locust/test/test_fasthttp.py::TestFastHttpUserClass::test_client_get PASSED [ 18%] locust/test/test_fasthttp.py::TestFastHttpUserClass::test_client_get_absolute_url PASSED [ 18%] locust/test/test_fasthttp.py::TestFastHttpUserClass::test_client_head PASSED [ 18%] locust/test/test_fasthttp.py::TestFastHttpUserClass::test_client_pool_concurrency PASSED [ 18%] locust/test/test_fasthttp.py::TestFastHttpUserClass::test_client_pool_per_user_instance PASSED [ 18%] locust/test/test_fasthttp.py::TestFastHttpUserClass::test_client_post PASSED [ 18%] locust/test/test_fasthttp.py::TestFastHttpUserClass::test_client_put PASSED [ 19%] locust/test/test_fasthttp.py::TestFastHttpUserClass::test_client_request_headers PASSED [ 19%] locust/test/test_fasthttp.py::TestFastHttpUserClass::test_complex_content_type PASSED [ 19%] locust/test/test_fasthttp.py::TestFastHttpUserClass::test_get_request PASSED [ 19%] locust/test/test_fasthttp.py::TestFastHttpUserClass::test_is_abstract PASSED [ 19%] locust/test/test_fasthttp.py::TestFastHttpUserClass::test_log_request_name_argument PASSED [ 20%] locust/test/test_fasthttp.py::TestFastHttpUserClass::test_max_redirect_setting PASSED [ 20%] locust/test/test_fasthttp.py::TestFastHttpUserClass::test_network_timeout_setting PASSED [ 20%] locust/test/test_fasthttp.py::TestFastHttpUserClass::test_redirect_url_original_path_as_name PASSED [ 20%] locust/test/test_fasthttp.py::TestFastHttpUserClass::test_shared_client_pool PASSED [ 20%] locust/test/test_fasthttp.py::TestFastHttpUserClass::test_slow_redirect PASSED [ 20%] locust/test/test_fasthttp.py::TestFastHttpCatchResponse::test_catch_response PASSED [ 21%] locust/test/test_fasthttp.py::TestFastHttpCatchResponse::test_catch_response_allow_404 PASSED [ 21%] locust/test/test_fasthttp.py::TestFastHttpCatchResponse::test_catch_response_connection_error_fail PASSED [ 21%] locust/test/test_fasthttp.py::TestFastHttpCatchResponse::test_catch_response_connection_error_success PASSED [ 21%] locust/test/test_fasthttp.py::TestFastHttpCatchResponse::test_catch_response_http_fail PASSED [ 21%] locust/test/test_fasthttp.py::TestFastHttpCatchResponse::test_catch_response_http_manual_fail PASSED [ 22%] locust/test/test_fasthttp.py::TestFastHttpCatchResponse::test_catch_response_http_manual_success PASSED [ 22%] locust/test/test_fasthttp.py::TestFastHttpCatchResponse::test_catch_response_missing_with_block PASSED [ 22%] locust/test/test_fasthttp.py::TestFastHttpCatchResponse::test_interrupt_taskset_with_catch_response PASSED [ 22%] locust/test/test_fasthttp.py::TestFastHttpCatchResponse::test_missing_catch_response_true PASSED [ 22%] locust/test/test_fasthttp.py::TestFastHttpCatchResponse::test_rest_fail PASSED [ 22%] locust/test/test_fasthttp.py::TestFastHttpCatchResponse::test_rest_success PASSED [ 23%] locust/test/test_fasthttp.py::TestFastHttpSsl::test_ssl_request_insecure PASSED [ 23%] locust/test/test_http.py::TestHttpSession::test_catch_response_default_fail PASSED [ 23%] locust/test/test_http.py::TestHttpSession::test_catch_response_default_success PASSED [ 23%] locust/test/test_http.py::TestHttpSession::test_catch_response_fail_successful_request PASSED [ 23%] locust/test/test_http.py::TestHttpSession::test_catch_response_fail_successful_request_with_non_string_error_message PASSED [ 24%] locust/test/test_http.py::TestHttpSession::test_catch_response_missing_with_block PASSED [ 24%] locust/test/test_http.py::TestHttpSession::test_catch_response_multiple_failure_and_success PASSED [ 24%] locust/test/test_http.py::TestHttpSession::test_catch_response_pass_failed_request PASSED [ 24%] locust/test/test_http.py::TestHttpSession::test_catch_response_pass_failed_request_with_other_exception_within_block PASSED [ 24%] locust/test/test_http.py::TestHttpSession::test_catch_response_response_error PASSED [ 24%] locust/test/test_http.py::TestHttpSession::test_catch_response_timeout PASSED [ 25%] locust/test/test_http.py::TestHttpSession::test_catch_response_with_name_replacement PASSED [ 25%] locust/test/test_http.py::TestHttpSession::test_connection_error PASSED [ 25%] locust/test/test_http.py::TestHttpSession::test_context_in_success PASSED [ 25%] locust/test/test_http.py::TestHttpSession::test_cookie PASSED [ 25%] locust/test/test_http.py::TestHttpSession::test_delete PASSED [ 26%] locust/test/test_http.py::TestHttpSession::test_error_message PASSED [ 26%] locust/test/test_http.py::TestHttpSession::test_error_message_with_name_replacement PASSED [ 26%] locust/test/test_http.py::TestHttpSession::test_event_measure FAILED [ 26%] locust/test/test_http.py::TestHttpSession::test_get PASSED [ 26%] locust/test/test_http.py::TestHttpSession::test_get_with_params PASSED [ 26%] locust/test/test_http.py::TestHttpSession::test_head PASSED [ 27%] locust/test/test_http.py::TestHttpSession::test_missing_catch_response_true PASSED [ 27%] locust/test/test_http.py::TestHttpSession::test_options PASSED [ 27%] locust/test/test_http.py::TestHttpSession::test_post_redirect PASSED [ 27%] locust/test/test_http.py::TestHttpSession::test_response_parameter PASSED [ 27%] locust/test/test_http.py::TestHttpSession::test_slow_redirect PASSED [ 28%] locust/test/test_http.py::TestHttpSession::test_streaming_response PASSED [ 28%] locust/test/test_http.py::TestHttpSession::test_user_context PASSED [ 28%] locust/test/test_http.py::TestHttpSession::test_wrong_url PASSED [ 28%] locust/test/test_interruptable_task.py::TestInterruptableTask::test_interruptable_task PASSED [ 28%] locust/test/test_load_locustfile.py::TestLoadLocustfile::test_command_line_arguments_override_config_file PASSED [ 28%] locust/test/test_load_locustfile.py::TestLoadLocustfile::test_create_environment PASSED [ 29%] locust/test/test_load_locustfile.py::TestLoadLocustfile::test_is_user_class PASSED [ 29%] locust/test/test_load_locustfile.py::TestLoadLocustfile::test_load_locust_file_called_locust_dot_py PASSED [ 29%] locust/test/test_load_locustfile.py::TestLoadLocustfile::test_load_locust_file_from_absolute_path PASSED [ 29%] locust/test/test_load_locustfile.py::TestLoadLocustfile::test_load_locust_file_from_relative_path PASSED [ 29%] locust/test/test_load_locustfile.py::TestLoadLocustfile::test_load_locust_file_with_a_dot_in_filename PASSED [ 30%] locust/test/test_load_locustfile.py::TestLoadLocustfile::test_locustfile_can_be_set_in_config_file PASSED [ 30%] locust/test/test_load_locustfile.py::TestLoadLocustfile::test_locustfile_from_url FAILED [ 30%] locust/test/test_load_locustfile.py::TestLoadLocustfile::test_return_docstring_and_user_classes PASSED [ 30%] locust/test/test_load_locustfile.py::TestLoadLocustfile::test_specify_config_file PASSED [ 30%] locust/test/test_load_locustfile.py::TestLoadLocustfile::test_with_abstract_shape_class PASSED [ 30%] locust/test/test_load_locustfile.py::TestLoadLocustfile::test_with_multiple_shape_classes PASSED [ 31%] locust/test/test_load_locustfile.py::TestLoadLocustfile::test_with_not_imported_shape_class PASSED [ 31%] locust/test/test_load_locustfile.py::TestLoadLocustfile::test_with_shape_class PASSED [ 31%] locust/test/test_locust_class.py::TestTaskSet::test_on_start PASSED [ 31%] locust/test/test_locust_class.py::TestTaskSet::test_on_start_interrupt PASSED [ 31%] locust/test/test_locust_class.py::TestTaskSet::test_on_stop_interrupt PASSED [ 32%] locust/test/test_locust_class.py::TestTaskSet::test_on_stop_interrupt_reschedule PASSED [ 32%] locust/test/test_locust_class.py::TestTaskSet::test_on_stop_when_locust_stops PASSED [ 32%] locust/test/test_locust_class.py::TestTaskSet::test_parent_attribute PASSED [ 32%] locust/test/test_locust_class.py::TestTaskSet::test_schedule_task PASSED [ 32%] locust/test/test_locust_class.py::TestTaskSet::test_schedule_task_bound_method PASSED [ 32%] locust/test/test_locust_class.py::TestTaskSet::test_sub_taskset PASSED [ 33%] locust/test/test_locust_class.py::TestTaskSet::test_sub_taskset_tasks_decorator PASSED [ 33%] locust/test/test_locust_class.py::TestTaskSet::test_task_decorator_on_taskset PASSED [ 33%] locust/test/test_locust_class.py::TestTaskSet::test_task_decorator_ratio PASSED [ 33%] locust/test/test_locust_class.py::TestTaskSet::test_task_decorator_with_or_without_argument PASSED [ 33%] locust/test/test_locust_class.py::TestTaskSet::test_task_ratio PASSED [ 34%] locust/test/test_locust_class.py::TestTaskSet::test_tasks_missing_from_user_gives_user_friendly_exception PASSED [ 34%] locust/test/test_locust_class.py::TestTaskSet::test_tasks_missing_gives_user_friendly_exception PASSED [ 34%] locust/test/test_locust_class.py::TestTaskSet::test_tasks_on_abstract_locust PASSED [ 34%] locust/test/test_locust_class.py::TestTaskSet::test_tasks_on_locust PASSED [ 34%] locust/test/test_locust_class.py::TestTaskSet::test_taskset_inheritance PASSED [ 34%] locust/test/test_locust_class.py::TestTaskSet::test_taskset_on_abstract_locust PASSED [ 35%] locust/test/test_locust_class.py::TestTaskSet::test_user_is_read_only PASSED [ 35%] locust/test/test_locust_class.py::TestTaskSet::test_wait_function PASSED [ 35%] locust/test/test_locust_class.py::TestLocustClass::test_deprecated_locust_class PASSED [ 35%] locust/test/test_locust_class.py::TestLocustClass::test_locust_forced_stop PASSED [ 35%] locust/test/test_locust_class.py::TestLocustClass::test_locust_graceful_stop PASSED [ 36%] locust/test/test_locust_class.py::TestLocustClass::test_locust_on_start PASSED [ 36%] locust/test/test_locust_class.py::TestLocustClass::test_locust_on_stop PASSED [ 36%] locust/test/test_locust_class.py::TestLocustClass::test_locust_start PASSED [ 36%] locust/test/test_locust_class.py::TestLocustClass::test_locust_wait PASSED [ 36%] locust/test/test_locust_class.py::TestWebLocustClass::test_client_basic_auth PASSED [ 36%] locust/test/test_locust_class.py::TestWebLocustClass::test_client_delete PASSED [ 37%] locust/test/test_locust_class.py::TestWebLocustClass::test_client_get PASSED [ 37%] locust/test/test_locust_class.py::TestWebLocustClass::test_client_get_absolute_url PASSED [ 37%] locust/test/test_locust_class.py::TestWebLocustClass::test_client_head PASSED [ 37%] locust/test/test_locust_class.py::TestWebLocustClass::test_client_post PASSED [ 37%] locust/test/test_locust_class.py::TestWebLocustClass::test_client_put PASSED [ 38%] locust/test/test_locust_class.py::TestWebLocustClass::test_client_request_headers PASSED [ 38%] locust/test/test_locust_class.py::TestWebLocustClass::test_get_request PASSED [ 38%] locust/test/test_locust_class.py::TestWebLocustClass::test_log_request_name_argument PASSED [ 38%] locust/test/test_locust_class.py::TestWebLocustClass::test_redirect_url_original_path_as_name PASSED [ 38%] locust/test/test_locust_class.py::TestCatchResponse::test_catch_response PASSED [ 38%] locust/test/test_locust_class.py::TestCatchResponse::test_catch_response_allow_404 PASSED [ 39%] locust/test/test_locust_class.py::TestCatchResponse::test_catch_response_connection_error_fail PASSED [ 39%] locust/test/test_locust_class.py::TestCatchResponse::test_catch_response_connection_error_success PASSED [ 39%] locust/test/test_locust_class.py::TestCatchResponse::test_catch_response_http_fail PASSED [ 39%] locust/test/test_locust_class.py::TestCatchResponse::test_catch_response_http_manual_fail PASSED [ 39%] locust/test/test_locust_class.py::TestCatchResponse::test_catch_response_http_manual_success PASSED [ 40%] locust/test/test_locust_class.py::TestCatchResponse::test_interrupt_taskset_with_catch_response PASSED [ 40%] locust/test/test_log.py::TestGreenletExceptionLogger::test_greenlet_exception_logger PASSED [ 40%] locust/test/test_log.py::TestLoggingOptions::test_log_to_file FAILED [ 40%] locust/test/test_log.py::TestLoggingOptions::test_logging_output FAILED [ 40%] locust/test/test_log.py::TestLoggingOptions::test_skip_logging FAILED [ 40%] locust/test/test_log.py::TestLoggingOptions::test_user_broken_on_start FAILED [ 41%] locust/test/test_main.py::StandaloneIntegrationTests::test_autostart_multiple_locustfiles_with_shape FAILED [ 41%] locust/test/test_main.py::StandaloneIntegrationTests::test_autostart_w_load_shape FAILED [ 41%] locust/test/test_main.py::StandaloneIntegrationTests::test_autostart_w_run_time FAILED [ 41%] locust/test/test_main.py::StandaloneIntegrationTests::test_autostart_wo_run_time FAILED [ 41%] locust/test/test_main.py::StandaloneIntegrationTests::test_command_line_user_selection FAILED [ 42%] locust/test/test_main.py::StandaloneIntegrationTests::test_custom_arguments FAILED [ 42%] locust/test/test_main.py::StandaloneIntegrationTests::test_custom_arguments_in_file FAILED [ 42%] locust/test/test_main.py::StandaloneIntegrationTests::test_custom_exit_code FAILED [ 42%] locust/test/test_main.py::StandaloneIntegrationTests::test_default_headless_spawn_options FAILED [ 42%] locust/test/test_main.py::StandaloneIntegrationTests::test_default_headless_spawn_options_with_shape FAILED [ 42%] locust/test/test_main.py::StandaloneIntegrationTests::test_error_when_duplicate_shape_class_names FAILED [ 43%] locust/test/test_main.py::StandaloneIntegrationTests::test_error_when_duplicate_userclass_names FAILED [ 43%] locust/test/test_main.py::StandaloneIntegrationTests::test_error_when_locustfiles_directory_is_empty FAILED [ 43%] locust/test/test_main.py::StandaloneIntegrationTests::test_error_when_no_tasks_match_tags FAILED [ 43%] locust/test/test_main.py::StandaloneIntegrationTests::test_error_when_providing_both_run_time_and_a_shape_class FAILED [ 43%] locust/test/test_main.py::StandaloneIntegrationTests::test_graceful_exit_when_keyboard_interrupt FAILED [ 44%] locust/test/test_main.py::StandaloneIntegrationTests::test_headless_spawn_options_wo_run_time FAILED [ 44%] locust/test/test_main.py::StandaloneIntegrationTests::test_help_arg FAILED [ 44%] locust/test/test_main.py::StandaloneIntegrationTests::test_html_report_option FAILED [ 44%] locust/test/test_main.py::StandaloneIntegrationTests::test_input FAILED [ 44%] locust/test/test_main.py::StandaloneIntegrationTests::test_invalid_percentile_parameter FAILED [ 44%] locust/test/test_main.py::StandaloneIntegrationTests::test_invalid_stop_timeout_string FAILED [ 45%] locust/test/test_main.py::StandaloneIntegrationTests::test_no_error_when_same_userclass_in_two_files FAILED [ 45%] locust/test/test_main.py::StandaloneIntegrationTests::test_percentile_parameter FAILED [ 45%] locust/test/test_main.py::StandaloneIntegrationTests::test_percentiles_to_statistics FAILED [ 45%] locust/test/test_main.py::StandaloneIntegrationTests::test_run_autostart_with_multiple_locustfiles FAILED [ 45%] locust/test/test_main.py::StandaloneIntegrationTests::test_run_headless_with_multiple_locustfiles FAILED [ 46%] locust/test/test_main.py::StandaloneIntegrationTests::test_run_headless_with_multiple_locustfiles_with_shape FAILED [ 46%] locust/test/test_main.py::StandaloneIntegrationTests::test_run_with_userclass_picker FAILED [ 46%] locust/test/test_main.py::StandaloneIntegrationTests::test_shape_class_log_disabled_parameters FAILED [ 46%] locust/test/test_main.py::StandaloneIntegrationTests::test_shape_class_with_use_common_options FAILED [ 46%] locust/test/test_main.py::StandaloneIntegrationTests::test_spawing_with_fixed_multiple_locustfiles FAILED [ 46%] locust/test/test_main.py::StandaloneIntegrationTests::test_spawning_with_fixed FAILED [ 47%] locust/test/test_main.py::StandaloneIntegrationTests::test_web_options FAILED [ 47%] locust/test/test_main.py::StandaloneIntegrationTests::test_webserver FAILED [ 47%] locust/test/test_main.py::StandaloneIntegrationTests::test_webserver_multiple_locustfiles FAILED [ 47%] locust/test/test_main.py::StandaloneIntegrationTests::test_webserver_multiple_locustfiles_in_directory FAILED [ 47%] locust/test/test_main.py::StandaloneIntegrationTests::test_webserver_multiple_locustfiles_with_shape FAILED [ 48%] locust/test/test_main.py::DistributedIntegrationTests::test_distributed FAILED [ 48%] locust/test/test_main.py::DistributedIntegrationTests::test_distributed_events FAILED [ 48%] locust/test/test_main.py::DistributedIntegrationTests::test_distributed_report_timeout_expired FAILED [ 48%] locust/test/test_main.py::DistributedIntegrationTests::test_distributed_tags FAILED [ 48%] locust/test/test_main.py::DistributedIntegrationTests::test_distributed_with_locustfile_distribution_not_plain_filename FAILED [ 48%] locust/test/test_main.py::DistributedIntegrationTests::test_expect_workers FAILED [ 49%] locust/test/test_main.py::DistributedIntegrationTests::test_json_schema FAILED [ 49%] locust/test/test_main.py::DistributedIntegrationTests::test_locustfile_distribution FAILED [ 49%] locust/test/test_main.py::DistributedIntegrationTests::test_locustfile_distribution_with_workers_started_first FAILED [ 49%] locust/test/test_main.py::DistributedIntegrationTests::test_processes FAILED [ 49%] locust/test/test_main.py::DistributedIntegrationTests::test_processes_autodetect FAILED [ 50%] locust/test/test_main.py::DistributedIntegrationTests::test_processes_ctrl_c FAILED [ 50%] locust/test/test_main.py::DistributedIntegrationTests::test_processes_error_doesnt_blow_up_completely FAILED [ 50%] locust/test/test_main.py::DistributedIntegrationTests::test_processes_separate_worker FAILED [ 50%] locust/test/test_main.py::DistributedIntegrationTests::test_processes_workers_quit_unexpected FAILED [ 50%] locust/test/test_main.py::DistributedIntegrationTests::test_worker_indexes FAILED [ 51%] locust/test/test_main.py::DistributedIntegrationTests::test_workers_shut_down_if_master_is_gone FAILED [ 51%] locust/test/test_parser.py::TestParser::test_default PASSED [ 51%] locust/test/test_parser.py::TestParser::test_parse_options_from_conf_file PASSED [ 51%] locust/test/test_parser.py::TestParser::test_parse_options_from_toml_file PASSED [ 51%] locust/test/test_parser.py::TestParser::test_reset_stats PASSED [ 51%] locust/test/test_parser.py::TestParser::test_skip_log_setup PASSED [ 52%] locust/test/test_parser.py::TestArgumentParser::test_csv_full_history_requires_csv PASSED [ 52%] locust/test/test_parser.py::TestArgumentParser::test_custom_argument PASSED [ 52%] locust/test/test_parser.py::TestArgumentParser::test_custom_argument_help_message PASSED [ 52%] locust/test/test_parser.py::TestArgumentParser::test_custom_argument_included_in_web_ui PASSED [ 52%] locust/test/test_parser.py::TestArgumentParser::test_parse_locustfile PASSED [ 53%] locust/test/test_parser.py::TestArgumentParser::test_parse_locustfile_empty_directory_error PASSED [ 53%] locust/test/test_parser.py::TestArgumentParser::test_parse_locustfile_invalid_directory_error PASSED [ 53%] locust/test/test_parser.py::TestArgumentParser::test_parse_locustfile_multiple_files PASSED [ 53%] locust/test/test_parser.py::TestArgumentParser::test_parse_locustfile_with_directory PASSED [ 53%] locust/test/test_parser.py::TestArgumentParser::test_parse_locustfile_with_directory_ignores_invalid_filenames PASSED [ 53%] locust/test/test_parser.py::TestArgumentParser::test_parse_locustfile_with_nested_directory PASSED [ 54%] locust/test/test_parser.py::TestArgumentParser::test_parse_options PASSED [ 54%] locust/test/test_parser.py::TestArgumentParser::test_parse_options_from_env PASSED [ 54%] locust/test/test_parser.py::TestArgumentParser::test_unknown_command_line_arg PASSED [ 54%] locust/test/test_parser.py::TestFindLocustfiles::test_find_locustfiles_error_for_invalid_file_extension PASSED [ 54%] locust/test/test_parser.py::TestFindLocustfiles::test_find_locustfiles_error_if_directory_doesnt_exist PASSED [ 55%] locust/test/test_parser.py::TestFindLocustfiles::test_find_locustfiles_error_if_invalid_directory PASSED [ 55%] locust/test/test_parser.py::TestFindLocustfiles::test_find_locustfiles_error_if_multiple_values_for_directory PASSED [ 55%] locust/test/test_parser.py::TestFindLocustfiles::test_find_locustfiles_ignores_invalid_files_in_directory PASSED [ 55%] locust/test/test_parser.py::TestFindLocustfiles::test_find_locustfiles_with_is_directory PASSED [ 55%] locust/test/test_parser.py::TestFindLocustfiles::test_find_locustfiles_with_multiple_locustfiles PASSED [ 55%] locust/test/test_parser.py::TestLocustfileIsDirectory::test_locustfile_is_directory_false_if_file_and_directory_share_the_same_name PASSED [ 56%] locust/test/test_parser.py::TestLocustfileIsDirectory::test_locustfile_is_directory_multiple_locustfiles PASSED [ 56%] locust/test/test_parser.py::TestLocustfileIsDirectory::test_locustfile_is_directory_single_locustfile PASSED [ 56%] locust/test/test_parser.py::TestLocustfileIsDirectory::test_locustfile_is_directory_single_locustfile_without_file_extension PASSED [ 56%] locust/test/test_parser.py::TestLocustfileIsDirectory::test_locustfile_is_directory_true_if_directory PASSED [ 56%] locust/test/test_runners.py::TestLocustRunner::test_attributes_populated_when_calling_start PASSED [ 57%] locust/test/test_runners.py::TestLocustRunner::test_can_call_stop_endpoint_if_currently_swarming PASSED [ 57%] locust/test/test_runners.py::TestLocustRunner::test_change_user_count_during_spawning PASSED [ 57%] locust/test/test_runners.py::TestLocustRunner::test_cpu_warning FAILED [ 57%] locust/test/test_runners.py::TestLocustRunner::test_custom_dispatcher_class PASSED [ 57%] locust/test/test_runners.py::TestLocustRunner::test_custom_message PASSED [ 57%] locust/test/test_runners.py::TestLocustRunner::test_duplicate_message_handler_registration PASSED [ 58%] locust/test/test_runners.py::TestLocustRunner::test_host_class_attribute_from_web PASSED [ 58%] locust/test/test_runners.py::TestLocustRunner::test_kill_locusts PASSED [ 58%] locust/test/test_runners.py::TestLocustRunner::test_no_reset_stats PASSED [ 58%] locust/test/test_runners.py::TestLocustRunner::test_reset_stats PASSED [ 58%] locust/test/test_runners.py::TestLocustRunner::test_runner_quit_can_run_on_stop_for_multiple_users_concurrently PASSED [ 59%] locust/test/test_runners.py::TestLocustRunner::test_runner_reference_on_environment PASSED [ 59%] locust/test/test_runners.py::TestLocustRunner::test_start_event PASSED [ 59%] locust/test/test_runners.py::TestLocustRunner::test_stop_event PASSED [ 59%] locust/test/test_runners.py::TestLocustRunner::test_stop_event_quit PASSED [ 59%] locust/test/test_runners.py::TestLocustRunner::test_stop_event_stop_and_quit PASSED [ 59%] locust/test/test_runners.py::TestLocustRunner::test_stop_users_count PASSED [ 60%] locust/test/test_runners.py::TestLocustRunner::test_stop_users_with_spawn_rate FAILED [ 60%] locust/test/test_runners.py::TestLocustRunner::test_stopping_event PASSED [ 60%] locust/test/test_runners.py::TestLocustRunner::test_swarm_endpoint_is_non_blocking PASSED [ 60%] locust/test/test_runners.py::TestLocustRunner::test_target_user_count_is_set_before_ramp_up PASSED [ 60%] locust/test/test_runners.py::TestLocustRunner::test_undefined_custom_message PASSED [ 61%] locust/test/test_runners.py::TestLocustRunner::test_user_classes_count PASSED [ 61%] locust/test/test_runners.py::TestLocustRunner::test_user_count_starts_from_specified_amount_when_creating_new_test_after_previous_step_has_been_stopped PASSED [ 61%] locust/test/test_runners.py::TestLocustRunner::test_users_can_call_runner_quit_without_deadlocking PASSED [ 61%] locust/test/test_runners.py::TestMasterRunner::test_attributes_populated_when_calling_start FAILED [ 61%] locust/test/test_runners.py::TestMasterRunner::test_custom_message_receive PASSED [ 61%] locust/test/test_runners.py::TestMasterRunner::test_custom_message_send PASSED [ 62%] locust/test/test_runners.py::TestMasterRunner::test_custom_shape_scale_down FAILED [ 62%] locust/test/test_runners.py::TestMasterRunner::test_custom_shape_scale_interval FAILED [ 62%] locust/test/test_runners.py::TestMasterRunner::test_custom_shape_scale_up FAILED [ 62%] locust/test/test_runners.py::TestMasterRunner::test_exception_in_task PASSED [ 62%] locust/test/test_runners.py::TestMasterRunner::test_exception_is_caught PASSED [ 63%] locust/test/test_runners.py::TestMasterRunner::test_last_worker_missing_stops_test FAILED [ 63%] locust/test/test_runners.py::TestMasterRunner::test_last_worker_quitting_stops_test FAILED [ 63%] locust/test/test_runners.py::TestMasterRunner::test_master_current_response_times PASSED [ 63%] locust/test/test_runners.py::TestMasterRunner::test_master_discard_first_client_ready FAILED [ 63%] locust/test/test_runners.py::TestMasterRunner::test_master_marks_downed_workers_as_missing FAILED [ 63%] locust/test/test_runners.py::TestMasterRunner::test_master_reset_connection FAILED [ 64%] locust/test/test_runners.py::TestMasterRunner::test_master_total_stats PASSED [ 64%] locust/test/test_runners.py::TestMasterRunner::test_master_total_stats_with_none_response_times PASSED [ 64%] locust/test/test_runners.py::TestMasterRunner::test_rebalance_locust_users_on_worker_connect FAILED [ 64%] locust/test/test_runners.py::TestMasterRunner::test_reset_connection_after_RPCError FAILED [ 64%] locust/test/test_runners.py::TestMasterRunner::test_sends_spawn_data_to_ready_running_spawning_workers PASSED [ 65%] locust/test/test_runners.py::TestMasterRunner::test_spawn_correct_worker_indexes FAILED [ 65%] locust/test/test_runners.py::TestMasterRunner::test_spawn_fewer_locusts_than_workers FAILED [ 65%] locust/test/test_runners.py::TestMasterRunner::test_spawn_uneven_locusts FAILED [ 65%] locust/test/test_runners.py::TestMasterRunner::test_spawn_zero_locusts PASSED [ 65%] locust/test/test_runners.py::TestMasterRunner::test_start_event FAILED [ 65%] locust/test/test_runners.py::TestMasterRunner::test_stop_event FAILED [ 66%] locust/test/test_runners.py::TestMasterRunner::test_stop_event_quit FAILED [ 66%] locust/test/test_runners.py::TestMasterRunner::test_undefined_custom_message_receive PASSED [ 66%] locust/test/test_runners.py::TestMasterRunner::test_unknown_host_sends_message_to_master FAILED [ 66%] locust/test/test_runners.py::TestMasterRunner::test_wait_for_workers_report_after_ramp_up PASSED [ 66%] locust/test/test_runners.py::TestMasterRunner::test_worker_connect FAILED [ 67%] locust/test/test_runners.py::TestMasterRunner::test_worker_connect_with_special_versions FAILED [ 67%] locust/test/test_runners.py::TestMasterRunner::test_worker_missing_after_heartbeat_dead_interval FAILED [ 67%] locust/test/test_runners.py::TestMasterRunner::test_worker_sends_bad_message_to_master FAILED [ 67%] locust/test/test_runners.py::TestMasterRunner::test_worker_sends_unrecognized_message_to_master FAILED [ 67%] locust/test/test_runners.py::TestMasterRunner::test_worker_stats_report_median PASSED [ 67%] locust/test/test_runners.py::TestMasterRunner::test_worker_stats_report_with_none_response_times PASSED [ 68%] locust/test/test_runners.py::TestWorkerRunner::test_change_user_count_during_spawning PASSED [ 68%] locust/test/test_runners.py::TestWorkerRunner::test_computed_properties PASSED [ 68%] locust/test/test_runners.py::TestWorkerRunner::test_custom_message_receive PASSED [ 68%] locust/test/test_runners.py::TestWorkerRunner::test_custom_message_send PASSED [ 68%] locust/test/test_runners.py::TestWorkerRunner::test_reset_rpc_connection_to_master PASSED [ 69%] locust/test/test_runners.py::TestWorkerRunner::test_spawn_message_with_older_timestamp_is_rejected PASSED [ 69%] locust/test/test_runners.py::TestWorkerRunner::test_start_event PASSED [ 69%] locust/test/test_runners.py::TestWorkerRunner::test_stop_event PASSED [ 69%] locust/test/test_runners.py::TestWorkerRunner::test_undefined_custom_message_receive PASSED [ 69%] locust/test/test_runners.py::TestWorkerRunner::test_worker_connect_failure PASSED [ 69%] locust/test/test_runners.py::TestWorkerRunner::test_worker_connect_success PASSED [ 70%] locust/test/test_runners.py::TestWorkerRunner::test_worker_heartbeat_messages_sent_to_master PASSED [ 70%] locust/test/test_runners.py::TestWorkerRunner::test_worker_messages_sent_to_master PASSED [ 70%] locust/test/test_runners.py::TestWorkerRunner::test_worker_stop_timeout PASSED [ 70%] locust/test/test_runners.py::TestWorkerRunner::test_worker_without_stop_timeout PASSED [ 70%] locust/test/test_runners.py::TestMessageSerializing::test_message_serialize PASSED [ 71%] locust/test/test_runners.py::TestStopTimeout::test_gracefully_handle_exceptions_in_listener PASSED [ 71%] locust/test/test_runners.py::TestStopTimeout::test_kill_locusts_with_stop_timeout FAILED [ 71%] locust/test/test_runners.py::TestStopTimeout::test_stop_timeout FAILED [ 71%] locust/test/test_runners.py::TestStopTimeout::test_stop_timeout_during_on_start FAILED [ 71%] locust/test/test_runners.py::TestStopTimeout::test_stop_timeout_exit_during_wait FAILED [ 71%] locust/test/test_runners.py::TestStopTimeout::test_stop_timeout_with_interrupt PASSED [ 72%] locust/test/test_runners.py::TestStopTimeout::test_stop_timeout_with_interrupt_no_reschedule FAILED [ 72%] locust/test/test_runners.py::TestStopTimeout::test_stop_timeout_with_ramp_down PASSED [ 72%] locust/test/test_runners.py::TestStopTimeout::test_users_can_call_runner_quit_with_stop_timeout PASSED [ 72%] locust/test/test_sequential_taskset.py::TestTaskSet::test_task_sequence_multiple_iterations PASSED [ 72%] locust/test/test_sequential_taskset.py::TestTaskSet::test_task_sequence_with_inheritance PASSED [ 73%] locust/test/test_sequential_taskset.py::TestTaskSet::test_task_sequence_with_list PASSED [ 73%] locust/test/test_sequential_taskset.py::TestTaskSet::test_task_sequence_with_methods PASSED [ 73%] locust/test/test_sequential_taskset.py::TestTaskSet::test_task_sequence_with_methods_and_list PASSED [ 73%] locust/test/test_stats.py::TestRequestStats::test_aggregation PASSED [ 73%] locust/test/test_stats.py::TestRequestStats::test_aggregation_last_request_timestamp PASSED [ 73%] locust/test/test_stats.py::TestRequestStats::test_aggregation_min_response_time PASSED [ 74%] locust/test/test_stats.py::TestRequestStats::test_aggregation_with_decimal_rounding PASSED [ 74%] locust/test/test_stats.py::TestRequestStats::test_aggregation_with_rounding PASSED [ 74%] locust/test/test_stats.py::TestRequestStats::test_avg PASSED [ 74%] locust/test/test_stats.py::TestRequestStats::test_avg_only_none PASSED [ 74%] locust/test/test_stats.py::TestRequestStats::test_current_fail_per_sec PASSED [ 75%] locust/test/test_stats.py::TestRequestStats::test_current_rps PASSED [ 75%] locust/test/test_stats.py::TestRequestStats::test_custom_percentile_list PASSED [ 75%] locust/test/test_stats.py::TestRequestStats::test_error_grouping PASSED [ 75%] locust/test/test_stats.py::TestRequestStats::test_error_grouping_errors_with_memory_addresses PASSED [ 75%] locust/test/test_stats.py::TestRequestStats::test_median PASSED [ 75%] locust/test/test_stats.py::TestRequestStats::test_median_out_of_min_max_bounds PASSED [ 76%] locust/test/test_stats.py::TestRequestStats::test_num_reqs_fails PASSED [ 76%] locust/test/test_stats.py::TestRequestStats::test_percentile PASSED [ 76%] locust/test/test_stats.py::TestRequestStats::test_percentile_rounded_down PASSED [ 76%] locust/test/test_stats.py::TestRequestStats::test_percentile_rounded_up PASSED [ 76%] locust/test/test_stats.py::TestRequestStats::test_reset PASSED [ 77%] locust/test/test_stats.py::TestRequestStats::test_reset_min_response_time PASSED [ 77%] locust/test/test_stats.py::TestRequestStats::test_rps_less_than_one_second PASSED [ 77%] locust/test/test_stats.py::TestRequestStats::test_serialize_through_message PASSED [ 77%] locust/test/test_stats.py::TestRequestStats::test_total_content_length PASSED [ 77%] locust/test/test_stats.py::TestRequestStats::test_total_rps PASSED [ 77%] locust/test/test_stats.py::TestStatsPrinting::test_print_error_report PASSED [ 78%] locust/test/test_stats.py::TestStatsPrinting::test_print_percentile_stats PASSED [ 78%] locust/test/test_stats.py::TestStatsPrinting::test_print_stats PASSED [ 78%] locust/test/test_stats.py::TestCsvStats::test_csv_stats_on_master_from_aggregated_stats PASSED [ 78%] locust/test/test_stats.py::TestCsvStats::test_csv_stats_writer PASSED [ 78%] locust/test/test_stats.py::TestCsvStats::test_csv_stats_writer_full_history PASSED [ 79%] locust/test/test_stats.py::TestCsvStats::test_requests_csv_quote_escaping PASSED [ 79%] locust/test/test_stats.py::TestCsvStats::test_stats_history FAILED [ 79%] locust/test/test_stats.py::TestCsvStats::test_user_count_in_csv_history_stats FAILED [ 79%] locust/test/test_stats.py::TestCsvStats::test_write_csv_files PASSED [ 79%] locust/test/test_stats.py::TestCsvStats::test_write_csv_files_full_history PASSED [ 79%] locust/test/test_stats.py::TestStatsEntryResponseTimesCache::test_diff_response_times_dicts PASSED [ 80%] locust/test/test_stats.py::TestStatsEntryResponseTimesCache::test_get_current_response_time_percentile PASSED [ 80%] locust/test/test_stats.py::TestStatsEntryResponseTimesCache::test_get_current_response_time_percentile_outside_cache_window PASSED [ 80%] locust/test/test_stats.py::TestStatsEntryResponseTimesCache::test_latest_total_response_times_pruned PASSED [ 80%] locust/test/test_stats.py::TestStatsEntryResponseTimesCache::test_response_times_cached PASSED [ 80%] locust/test/test_stats.py::TestStatsEntryResponseTimesCache::test_response_times_not_cached_if_not_enabled PASSED [ 81%] locust/test/test_stats.py::TestStatsEntry::test_fail_ratio_with_all_failures PASSED [ 81%] locust/test/test_stats.py::TestStatsEntry::test_fail_ratio_with_half_failures PASSED [ 81%] locust/test/test_stats.py::TestStatsEntry::test_fail_ratio_with_no_failures PASSED [ 81%] locust/test/test_stats.py::TestRequestStatsWithWebserver::test_request_connection_error PASSED [ 81%] locust/test/test_stats.py::TestRequestStatsWithWebserver::test_request_stats_content_length PASSED [ 81%] locust/test/test_stats.py::TestRequestStatsWithWebserver::test_request_stats_named_endpoint PASSED [ 82%] locust/test/test_stats.py::TestRequestStatsWithWebserver::test_request_stats_named_endpoint_rename_request PASSED [ 82%] locust/test/test_stats.py::TestRequestStatsWithWebserver::test_request_stats_named_endpoint_request_name PASSED [ 82%] locust/test/test_stats.py::TestRequestStatsWithWebserver::test_request_stats_no_content_length PASSED [ 82%] locust/test/test_stats.py::TestRequestStatsWithWebserver::test_request_stats_no_content_length_streaming PASSED [ 82%] locust/test/test_stats.py::TestRequestStatsWithWebserver::test_request_stats_put PASSED [ 83%] locust/test/test_stats.py::TestRequestStatsWithWebserver::test_request_stats_query_variables PASSED [ 83%] locust/test/test_stats.py::TestInspectUser::test_get_task_ratio_relative PASSED [ 83%] locust/test/test_stats.py::TestInspectUser::test_get_task_ratio_total PASSED [ 83%] locust/test/test_tags.py::TestTags::test_env_exclude_tags PASSED [ 83%] locust/test/test_tags.py::TestTags::test_env_include_tags PASSED [ 83%] locust/test/test_tags.py::TestTags::test_exclude_tags_under_user PASSED [ 84%] locust/test/test_tags.py::TestTags::test_excluding_tags PASSED [ 84%] locust/test/test_tags.py::TestTags::test_excluding_tags_with_weights PASSED [ 84%] locust/test/test_tags.py::TestTags::test_excluding_tasksets PASSED [ 84%] locust/test/test_tags.py::TestTags::test_include_tags_under_user PASSED [ 84%] locust/test/test_tags.py::TestTags::test_including_and_excluding PASSED [ 85%] locust/test/test_tags.py::TestTags::test_including_tags PASSED [ 85%] locust/test/test_tags.py::TestTags::test_including_tags_with_weights PASSED [ 85%] locust/test/test_tags.py::TestTags::test_including_tasksets PASSED [ 85%] locust/test/test_tags.py::TestTags::test_tagged_tasks_shared_across_tasksets PASSED [ 85%] locust/test/test_tags.py::TestTags::test_tagging PASSED [ 85%] locust/test/test_tags.py::TestTags::test_tagging_taskset PASSED [ 86%] locust/test/test_tags.py::TestTags::test_tagging_without_args_fails PASSED [ 86%] locust/test/test_taskratio.py::TestTaskRatio::test_task_ratio_command PASSED [ 86%] locust/test/test_taskratio.py::TestTaskRatio::test_task_ratio_command_with_locust_weight PASSED [ 86%] locust/test/test_users.py::TestUserClass::test_fullname_class_scoped PASSED [ 86%] locust/test/test_users.py::TestUserClass::test_fullname_function_scoped PASSED [ 87%] locust/test/test_users.py::TestUserClass::test_fullname_module_scoped PASSED [ 87%] locust/test/test_users.py::TestHttpUserWithWebserver::test_pool_manager_per_user_instance PASSED [ 87%] locust/test/test_users.py::TestHttpUserWithWebserver::test_shared_pool_manager PASSED [ 87%] locust/test/test_util.py::TestParseTimespan::test_parse_timespan PASSED [ 87%] locust/test/test_util.py::TestParseTimespan::test_parse_timespan_invalid_values PASSED [ 87%] locust/test/test_util.py::TestRounding::test_rounding_down PASSED [ 88%] locust/test/test_util.py::TestRounding::test_rounding_up PASSED [ 88%] locust/test/test_wait_time.py::TestWaitTime::test_between PASSED [ 88%] locust/test/test_wait_time.py::TestWaitTime::test_constant PASSED [ 88%] locust/test/test_wait_time.py::TestWaitTime::test_constant_throughput FAILED [ 88%] locust/test/test_wait_time.py::TestWaitTime::test_default_wait_time FAILED [ 89%] locust/test/test_web.py::TestWebUI::test_custom_argument_dropdown PASSED [ 89%] locust/test/test_web.py::TestWebUI::test_custom_shape_deactivate_num_users_and_spawn_rate PASSED [ 89%] locust/test/test_web.py::TestWebUI::test_custom_shape_with_use_common_options_keep_num_users_and_spawn_rate PASSED [ 89%] locust/test/test_web.py::TestWebUI::test_exceptions PASSED [ 89%] locust/test/test_web.py::TestWebUI::test_exceptions_csv PASSED [ 89%] locust/test/test_web.py::TestWebUI::test_failure_stats_csv PASSED [ 90%] locust/test/test_web.py::TestWebUI::test_host_value_from_multiple_user_classes PASSED [ 90%] locust/test/test_web.py::TestWebUI::test_host_value_from_multiple_user_classes_different_hosts PASSED [ 90%] locust/test/test_web.py::TestWebUI::test_host_value_from_user_class PASSED [ 90%] locust/test/test_web.py::TestWebUI::test_html_stats_report PASSED [ 90%] locust/test/test_web.py::TestWebUI::test_index PASSED [ 91%] locust/test/test_web.py::TestWebUI::test_index_with_spawn_options PASSED [ 91%] locust/test/test_web.py::TestWebUI::test_logs PASSED [ 91%] locust/test/test_web.py::TestWebUI::test_report_download PASSED [ 91%] locust/test/test_web.py::TestWebUI::test_report_exceptions PASSED [ 91%] locust/test/test_web.py::TestWebUI::test_report_host PASSED [ 91%] locust/test/test_web.py::TestWebUI::test_report_host2 PASSED [ 92%] locust/test/test_web.py::TestWebUI::test_report_page PASSED [ 92%] locust/test/test_web.py::TestWebUI::test_report_page_empty_stats PASSED [ 92%] locust/test/test_web.py::TestWebUI::test_request_stats_csv PASSED [ 92%] locust/test/test_web.py::TestWebUI::test_request_stats_full_history_csv_not_present PASSED [ 92%] locust/test/test_web.py::TestWebUI::test_request_stats_with_errors PASSED [ 93%] locust/test/test_web.py::TestWebUI::test_reset_stats PASSED [ 93%] locust/test/test_web.py::TestWebUI::test_stats PASSED [ 93%] locust/test/test_web.py::TestWebUI::test_stats_cache PASSED [ 93%] locust/test/test_web.py::TestWebUI::test_stats_no_data PASSED [ 93%] locust/test/test_web.py::TestWebUI::test_stats_rounding PASSED [ 93%] locust/test/test_web.py::TestWebUI::test_swarm_custom_argument PASSED [ 94%] locust/test/test_web.py::TestWebUI::test_swarm_defaults_to_all_available_userclasses_when_userclass_picker_is_active_and_no_userclass_in_payload PASSED [ 94%] locust/test/test_web.py::TestWebUI::test_swarm_error_when_userclass_picker_is_active_but_no_available_userclasses PASSED [ 94%] locust/test/test_web.py::TestWebUI::test_swarm_host_value_not_specified PASSED [ 94%] locust/test/test_web.py::TestWebUI::test_swarm_host_value_specified PASSED [ 94%] locust/test/test_web.py::TestWebUI::test_swarm_multiple_userclasses_specified PASSED [ 95%] locust/test/test_web.py::TestWebUI::test_swarm_run_time PASSED [ 95%] locust/test/test_web.py::TestWebUI::test_swarm_run_time_empty_input PASSED [ 95%] locust/test/test_web.py::TestWebUI::test_swarm_run_time_invalid_input PASSED [ 95%] locust/test/test_web.py::TestWebUI::test_swarm_shape_class_defaults_to_none_when_userclass_picker_is_active PASSED [ 95%] locust/test/test_web.py::TestWebUI::test_swarm_shape_class_is_updated_when_userclass_picker_is_active PASSED [ 95%] locust/test/test_web.py::TestWebUI::test_swarm_shape_class_specified PASSED [ 96%] locust/test/test_web.py::TestWebUI::test_swarm_updates_parsed_options_when_multiple_userclasses_specified PASSED [ 96%] locust/test/test_web.py::TestWebUI::test_swarm_updates_parsed_options_when_single_userclass_specified PASSED [ 96%] locust/test/test_web.py::TestWebUI::test_swarm_userclass_shapeclass_ignored_when_userclass_picker_is_inactive PASSED [ 96%] locust/test/test_web.py::TestWebUI::test_swarm_userclass_specified PASSED [ 96%] locust/test/test_web.py::TestWebUI::test_swarm_uses_pre_selected_user_classes_when_empty_payload_and_test_is_already_running_with_class_picker PASSED [ 97%] locust/test/test_web.py::TestWebUI::test_template_args PASSED [ 97%] locust/test/test_web.py::TestWebUI::test_update_user_endpoint PASSED [ 97%] locust/test/test_web.py::TestWebUI::test_web_ui_no_runner PASSED [ 97%] locust/test/test_web.py::TestWebUI::test_web_ui_reference_on_environment PASSED [ 97%] locust/test/test_web.py::TestWebUIAuth::test_index_with_web_login_enabled_no_user PASSED [ 97%] locust/test/test_web.py::TestWebUIAuth::test_index_with_web_login_enabled_valid_user PASSED [ 98%] locust/test/test_web.py::TestWebUIWithTLS::test_index_with_https PASSED [ 98%] locust/test/test_web.py::TestWebUIFullHistory::test_request_stats_full_history_csv PASSED [ 98%] locust/test/test_web.py::TestModernWebUI::test_html_stats_report PASSED [ 98%] locust/test/test_web.py::TestModernWebUI::test_index_with_modern_ui PASSED [ 98%] locust/test/test_web.py::TestModernWebUI::test_web_ui_no_runner PASSED [ 99%] locust/test/test_zmqrpc.py::ZMQRPC_tests::test_client_recv PASSED [ 99%] locust/test/test_zmqrpc.py::ZMQRPC_tests::test_client_retry PASSED [ 99%] locust/test/test_zmqrpc.py::ZMQRPC_tests::test_client_send PASSED [ 99%] locust/test/test_zmqrpc.py::ZMQRPC_tests::test_constructor PASSED [ 99%] locust/test/test_zmqrpc.py::ZMQRPC_tests::test_rpc_error PASSED [100%] =================================== FAILURES =================================== ______________________ TestHttpSession.test_event_measure ______________________ self = def test_event_measure(self): kwargs = {} def on_request(**kw): kwargs.update(**kw) self.environment.events.request.add_listener(on_request) with self.environment.events.request.measure("GET", "/test") as request_meta: time.sleep(0.001) > self.assertTrue(1 <= kwargs["response_time"] <= 1.5, kwargs["response_time"]) E AssertionError: False is not true : 3.958221997891087 locust/test/test_http.py:293: AssertionError _________________ TestLoadLocustfile.test_locustfile_from_url __________________ self = def _new_conn(self): """Establish a socket connection and set nodelay settings on it. :return: New socket connection. """ extra_kw = {} if self.source_address: extra_kw["source_address"] = self.source_address if self.socket_options: extra_kw["socket_options"] = self.socket_options try: > conn = connection.create_connection( (self._dns_host, self.port), self.timeout, **extra_kw ) /usr/lib/python3/dist-packages/urllib3/connection.py:174: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3/dist-packages/urllib3/util/connection.py:73: in create_connection for res in socket.getaddrinfo(host, port, family, socket.SOCK_STREAM): /usr/lib/python3/dist-packages/gevent/_socketcommon.py:225: in getaddrinfo addrlist = get_hub().resolver.getaddrinfo(host, port, family, type, proto, flags) /usr/lib/python3/dist-packages/gevent/resolver/thread.py:63: in getaddrinfo return self.pool.apply(_socket.getaddrinfo, args, kwargs) /usr/lib/python3/dist-packages/gevent/pool.py:161: in apply return self.spawn(func, *args, **kwds).get() src/gevent/event.py:329: in gevent._gevent_cevent.AsyncResult.get ??? src/gevent/event.py:359: in gevent._gevent_cevent.AsyncResult.get ??? src/gevent/event.py:347: in gevent._gevent_cevent.AsyncResult.get ??? src/gevent/event.py:327: in gevent._gevent_cevent.AsyncResult._raise_exception ??? /usr/lib/python3/dist-packages/gevent/_compat.py:49: in reraise raise value.with_traceback(tb) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ # Copyright (c) 2012 Denis Bilenko. See LICENSE for details. from __future__ import absolute_import from __future__ import division from __future__ import print_function import os import sys from greenlet import greenlet as RawGreenlet from gevent import monkey from gevent._compat import integer_types from gevent.event import AsyncResult from gevent.exceptions import InvalidThreadUseError from gevent.greenlet import Greenlet from gevent._hub_local import get_hub_if_exists from gevent.hub import _get_hub_noargs as get_hub from gevent.hub import getcurrent from gevent.hub import sleep from gevent.lock import Semaphore from gevent.pool import GroupMappingMixin from gevent.util import clear_stack_frames from gevent._threading import Queue from gevent._threading import EmptyTimeout from gevent._threading import start_new_thread from gevent._threading import get_thread_ident __all__ = [ 'ThreadPool', 'ThreadResult', ] def _format_hub(hub): if hub is None: return '' return '<%s at 0x%x thread_ident=0x%x>' % ( hub.__class__.__name__, id(hub), hub.thread_ident ) def _get_thread_profile(_sys=sys): if 'threading' in _sys.modules: return _sys.modules['threading']._profile_hook def _get_thread_trace(_sys=sys): if 'threading' in _sys.modules: return _sys.modules['threading']._trace_hook class _WorkerGreenlet(RawGreenlet): # Exists to produce a more useful repr for worker pool # threads/greenlets, and manage the communication of the worker # thread with the threadpool. # Inform the gevent.util.GreenletTree that this should be # considered the root (for printing purposes) greenlet_tree_is_root = True _thread_ident = 0 _exc_info = sys.exc_info _get_hub_if_exists = staticmethod(get_hub_if_exists) # We capture the hub each time through the loop in case its created # so we can destroy it after a fork. _hub_of_worker = None # The hub of the threadpool we're working for. Just for info. _hub = None # A cookie passed to task_queue.get() _task_queue_cookie = None # If not -1, how long to block waiting for a task before we # exit. _idle_task_timeout = -1 def __init__(self, threadpool): # Construct in the main thread (owner of the threadpool) # The parent greenlet and thread identifier will be set once the # new thread begins running. RawGreenlet.__init__(self) self._hub = threadpool.hub # Avoid doing any imports in the background thread if it's not # necessary (monkey.get_original imports if not patched). # Background imports can hang Python 2 (gevent's thread resolver runs in the BG, # and resolving may have to import the idna module, which needs an import lock, so # resolving at module scope) if monkey.is_module_patched('sys'): stderr = monkey.get_original('sys', 'stderr') else: stderr = sys.stderr self._stderr = stderr # We can capture the task_queue; even though it can change if the threadpool # is re-innitted, we won't be running in that case self._task_queue = threadpool.task_queue # type:gevent._threading.Queue self._task_queue_cookie = self._task_queue.allocate_cookie() self._unregister_worker = threadpool._unregister_worker self._idle_task_timeout = threadpool._idle_task_timeout threadpool._register_worker(self) try: start_new_thread(self._begin, ()) except: self._unregister_worker(self) raise def _begin(self, _get_c=getcurrent, _get_ti=get_thread_ident): # Pass arguments to avoid accessing globals during module shutdown. # we're in the new thread (but its root greenlet). Establish invariants and get going # by making this the current greenlet. self.parent = _get_c() # pylint:disable=attribute-defined-outside-init self._thread_ident = _get_ti() # ignore the parent attribute. (We can't set parent to None.) self.parent.greenlet_tree_is_ignored = True try: self.switch() # goto run() except: # pylint:disable=bare-except # run() will attempt to print any exceptions, but that might # not work during shutdown. sys.excepthook and such may be gone, # so things might not get printed at all except for a cryptic # message. This is especially true on Python 2 (doesn't seem to be # an issue on Python 3). pass def __fixup_hub_before_block(self): hub = self._get_hub_if_exists() # Don't create one; only set if a worker function did it if hub is not None: hub.name = 'ThreadPool Worker Hub' # While we block, don't let the monitoring thread, if any, # report us as blocked. Indeed, so long as we never # try to switch greenlets, don't report us as blocked--- # the threadpool is *meant* to run blocking tasks if hub is not None and hub.periodic_monitoring_thread is not None: hub.periodic_monitoring_thread.ignore_current_greenlet_blocking() self._hub_of_worker = hub @staticmethod def __print_tb(tb, stderr): # Extracted from traceback to avoid accessing any module # globals (these sometimes happen during interpreter shutdown; # see test__subprocess_interrupted) while tb is not None: f = tb.tb_frame lineno = tb.tb_lineno co = f.f_code filename = co.co_filename name = co.co_name print(' File "%s", line %d, in %s' % (filename, lineno, name), file=stderr) tb = tb.tb_next def _before_run_task(self, func, args, kwargs, thread_result, _sys=sys, _get_thread_profile=_get_thread_profile, _get_thread_trace=_get_thread_trace): # pylint:disable=unused-argument _sys.setprofile(_get_thread_profile()) _sys.settrace(_get_thread_trace()) def _after_run_task(self, func, args, kwargs, thread_result, _sys=sys): # pylint:disable=unused-argument _sys.setprofile(None) _sys.settrace(None) def __run_task(self, func, args, kwargs, thread_result): self._before_run_task(func, args, kwargs, thread_result) try: > thread_result.set(func(*args, **kwargs)) E socket.gaierror: [Errno -3] Temporary failure in name resolution /usr/lib/python3/dist-packages/gevent/threadpool.py:173: gaierror During handling of the above exception, another exception occurred: self = method = 'GET', url = '/locustio/locust/master/examples/basic.py', body = None headers = {'User-Agent': 'python-requests/2.31.0', 'Accept-Encoding': 'gzip, deflate, br', 'Accept': '*/*', 'Connection': 'keep-alive'} retries = Retry(total=0, connect=None, read=False, redirect=None, status=None) redirect = False, assert_same_host = False timeout = Timeout(connect=None, read=None, total=None), pool_timeout = None release_conn = False, chunked = False, body_pos = None response_kw = {'decode_content': False, 'preload_content': False} parsed_url = Url(scheme=None, auth=None, host=None, port=None, path='/locustio/locust/master/examples/basic.py', query=None, fragment=None) destination_scheme = None, conn = None, release_this_conn = True http_tunnel_required = False, err = None, clean_exit = False def urlopen( self, method, url, body=None, headers=None, retries=None, redirect=True, assert_same_host=True, timeout=_Default, pool_timeout=None, release_conn=None, chunked=False, body_pos=None, **response_kw ): """ Get a connection from the pool and perform an HTTP request. This is the lowest level call for making a request, so you'll need to specify all the raw details. .. note:: More commonly, it's appropriate to use a convenience method provided by :class:`.RequestMethods`, such as :meth:`request`. .. note:: `release_conn` will only behave as expected if `preload_content=False` because we want to make `preload_content=False` the default behaviour someday soon without breaking backwards compatibility. :param method: HTTP request method (such as GET, POST, PUT, etc.) :param url: The URL to perform the request on. :param body: Data to send in the request body, either :class:`str`, :class:`bytes`, an iterable of :class:`str`/:class:`bytes`, or a file-like object. :param headers: Dictionary of custom headers to send, such as User-Agent, If-None-Match, etc. If None, pool headers are used. If provided, these headers completely replace any pool-specific headers. :param retries: Configure the number of retries to allow before raising a :class:`~urllib3.exceptions.MaxRetryError` exception. Pass ``None`` to retry until you receive a response. Pass a :class:`~urllib3.util.retry.Retry` object for fine-grained control over different types of retries. Pass an integer number to retry connection errors that many times, but no other types of errors. Pass zero to never retry. If ``False``, then retries are disabled and any exception is raised immediately. Also, instead of raising a MaxRetryError on redirects, the redirect response will be returned. :type retries: :class:`~urllib3.util.retry.Retry`, False, or an int. :param redirect: If True, automatically handle redirects (status codes 301, 302, 303, 307, 308). Each redirect counts as a retry. Disabling retries will disable redirect, too. :param assert_same_host: If ``True``, will make sure that the host of the pool requests is consistent else will raise HostChangedError. When ``False``, you can use the pool on an HTTP proxy and request foreign hosts. :param timeout: If specified, overrides the default timeout for this one request. It may be a float (in seconds) or an instance of :class:`urllib3.util.Timeout`. :param pool_timeout: If set and the pool is set to block=True, then this method will block for ``pool_timeout`` seconds and raise EmptyPoolError if no connection is available within the time period. :param release_conn: If False, then the urlopen call will not release the connection back into the pool once a response is received (but will release if you read the entire contents of the response such as when `preload_content=True`). This is useful if you're not preloading the response's content immediately. You will need to call ``r.release_conn()`` on the response ``r`` to return the connection back into the pool. If None, it takes the value of ``response_kw.get('preload_content', True)``. :param chunked: If True, urllib3 will send the body using chunked transfer encoding. Otherwise, urllib3 will send the body using the standard content-length form. Defaults to False. :param int body_pos: Position to seek to in file-like body in the event of a retry or redirect. Typically this won't need to be set because urllib3 will auto-populate the value when needed. :param \\**response_kw: Additional parameters are passed to :meth:`urllib3.response.HTTPResponse.from_httplib` """ parsed_url = parse_url(url) destination_scheme = parsed_url.scheme if headers is None: headers = self.headers if not isinstance(retries, Retry): retries = Retry.from_int(retries, redirect=redirect, default=self.retries) if release_conn is None: release_conn = response_kw.get("preload_content", True) # Check host if assert_same_host and not self.is_same_host(url): raise HostChangedError(self, url, retries) # Ensure that the URL we're connecting to is properly encoded if url.startswith("/"): url = six.ensure_str(_encode_target(url)) else: url = six.ensure_str(parsed_url.url) conn = None # Track whether `conn` needs to be released before # returning/raising/recursing. Update this variable if necessary, and # leave `release_conn` constant throughout the function. That way, if # the function recurses, the original value of `release_conn` will be # passed down into the recursive call, and its value will be respected. # # See issue #651 [1] for details. # # [1] release_this_conn = release_conn http_tunnel_required = connection_requires_http_tunnel( self.proxy, self.proxy_config, destination_scheme ) # Merge the proxy headers. Only done when not using HTTP CONNECT. We # have to copy the headers dict so we can safely change it without those # changes being reflected in anyone else's copy. if not http_tunnel_required: headers = headers.copy() headers.update(self.proxy_headers) # Must keep the exception bound to a separate variable or else Python 3 # complains about UnboundLocalError. err = None # Keep track of whether we cleanly exited the except block. This # ensures we do proper cleanup in finally. clean_exit = False # Rewind body position, if needed. Record current position # for future rewinds in the event of a redirect/retry. body_pos = set_file_position(body, body_pos) try: # Request a connection from the queue. timeout_obj = self._get_timeout(timeout) conn = self._get_conn(timeout=pool_timeout) conn.timeout = timeout_obj.connect_timeout is_new_proxy_conn = self.proxy is not None and not getattr( conn, "sock", None ) if is_new_proxy_conn and http_tunnel_required: self._prepare_proxy(conn) # Make the request on the httplib connection object. > httplib_response = self._make_request( conn, method, url, timeout=timeout_obj, body=body, headers=headers, chunked=chunked, ) /usr/lib/python3/dist-packages/urllib3/connectionpool.py:716: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3/dist-packages/urllib3/connectionpool.py:405: in _make_request self._validate_conn(conn) /usr/lib/python3/dist-packages/urllib3/connectionpool.py:1059: in _validate_conn conn.connect() /usr/lib/python3/dist-packages/urllib3/connection.py:363: in connect self.sock = conn = self._new_conn() _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = def _new_conn(self): """Establish a socket connection and set nodelay settings on it. :return: New socket connection. """ extra_kw = {} if self.source_address: extra_kw["source_address"] = self.source_address if self.socket_options: extra_kw["socket_options"] = self.socket_options try: conn = connection.create_connection( (self._dns_host, self.port), self.timeout, **extra_kw ) except SocketTimeout: raise ConnectTimeoutError( self, "Connection to %s timed out. (connect timeout=%s)" % (self.host, self.timeout), ) except SocketError as e: > raise NewConnectionError( self, "Failed to establish a new connection: %s" % e ) E urllib3.exceptions.NewConnectionError: : Failed to establish a new connection: [Errno -3] Temporary failure in name resolution /usr/lib/python3/dist-packages/urllib3/connection.py:186: NewConnectionError During handling of the above exception, another exception occurred: self = request = , stream = False timeout = Timeout(connect=None, read=None, total=None), verify = True cert = None, proxies = OrderedDict({'no': 'localhost'}) def send( self, request, stream=False, timeout=None, verify=True, cert=None, proxies=None ): """Sends PreparedRequest object. Returns Response object. :param request: The :class:`PreparedRequest ` being sent. :param stream: (optional) Whether to stream the request content. :param timeout: (optional) How long to wait for the server to send data before giving up, as a float, or a :ref:`(connect timeout, read timeout) ` tuple. :type timeout: float or tuple or urllib3 Timeout object :param verify: (optional) Either a boolean, in which case it controls whether we verify the server's TLS certificate, or a string, in which case it must be a path to a CA bundle to use :param cert: (optional) Any user-provided SSL certificate to be trusted. :param proxies: (optional) The proxies dictionary to apply to the request. :rtype: requests.Response """ try: conn = self.get_connection(request.url, proxies) except LocationValueError as e: raise InvalidURL(e, request=request) self.cert_verify(conn, request.url, verify, cert) url = self.request_url(request, proxies) self.add_headers( request, stream=stream, timeout=timeout, verify=verify, cert=cert, proxies=proxies, ) chunked = not (request.body is None or "Content-Length" in request.headers) if isinstance(timeout, tuple): try: connect, read = timeout timeout = TimeoutSauce(connect=connect, read=read) except ValueError: raise ValueError( f"Invalid timeout {timeout}. Pass a (connect, read) timeout tuple, " f"or a single float to set both timeouts to the same value." ) elif isinstance(timeout, TimeoutSauce): pass else: timeout = TimeoutSauce(connect=timeout, read=timeout) try: > resp = conn.urlopen( method=request.method, url=url, body=request.body, headers=request.headers, redirect=False, assert_same_host=False, preload_content=False, decode_content=False, retries=self.max_retries, timeout=timeout, chunked=chunked, ) /usr/lib/python3/dist-packages/requests/adapters.py:486: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3/dist-packages/urllib3/connectionpool.py:800: in urlopen retries = retries.increment( _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = Retry(total=0, connect=None, read=False, redirect=None, status=None) method = 'GET', url = '/locustio/locust/master/examples/basic.py' response = None error = NewConnectionError(': Failed to establish a new connection: [Errno -3] Temporary failure in name resolution') _pool = _stacktrace = def increment( self, method=None, url=None, response=None, error=None, _pool=None, _stacktrace=None, ): """Return a new Retry object with incremented retry counters. :param response: A response object, or None, if the server did not return a response. :type response: :class:`~urllib3.response.HTTPResponse` :param Exception error: An error encountered during the request, or None if the response was received successfully. :return: A new ``Retry`` object. """ if self.total is False and error: # Disabled, indicate to re-raise the error. raise six.reraise(type(error), error, _stacktrace) total = self.total if total is not None: total -= 1 connect = self.connect read = self.read redirect = self.redirect status_count = self.status other = self.other cause = "unknown" status = None redirect_location = None if error and self._is_connection_error(error): # Connect retry? if connect is False: raise six.reraise(type(error), error, _stacktrace) elif connect is not None: connect -= 1 elif error and self._is_read_error(error): # Read retry? if read is False or not self._is_method_retryable(method): raise six.reraise(type(error), error, _stacktrace) elif read is not None: read -= 1 elif error: # Other retry? if other is not None: other -= 1 elif response and response.get_redirect_location(): # Redirect retry? if redirect is not None: redirect -= 1 cause = "too many redirects" redirect_location = response.get_redirect_location() status = response.status else: # Incrementing because of a server error like a 500 in # status_forcelist and the given method is in the allowed_methods cause = ResponseError.GENERIC_ERROR if response and response.status: if status_count is not None: status_count -= 1 cause = ResponseError.SPECIFIC_ERROR.format(status_code=response.status) status = response.status history = self.history + ( RequestHistory(method, url, error, status, redirect_location), ) new_retry = self.new( total=total, connect=connect, read=read, redirect=redirect, status=status_count, other=other, history=history, ) if new_retry.is_exhausted(): > raise MaxRetryError(_pool, url, error or ResponseError(cause)) E urllib3.exceptions.MaxRetryError: HTTPSConnectionPool(host='raw.githubusercontent.com', port=443): Max retries exceeded with url: /locustio/locust/master/examples/basic.py (Caused by NewConnectionError(': Failed to establish a new connection: [Errno -3] Temporary failure in name resolution')) /usr/lib/python3/dist-packages/urllib3/util/retry.py:592: MaxRetryError During handling of the above exception, another exception occurred: url = 'https://raw.githubusercontent.com/locustio/locust/master/examples/basic.py' def download_locustfile_from_url(url: str) -> str: try: > response = requests.get(url) locust/argument_parser.py:193: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3/dist-packages/requests/api.py:73: in get return request("get", url, params=params, **kwargs) /usr/lib/python3/dist-packages/requests/api.py:59: in request return session.request(method=method, url=url, **kwargs) /usr/lib/python3/dist-packages/requests/sessions.py:589: in request resp = self.send(prep, **send_kwargs) /usr/lib/python3/dist-packages/requests/sessions.py:703: in send r = adapter.send(request, **kwargs) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = request = , stream = False timeout = Timeout(connect=None, read=None, total=None), verify = True cert = None, proxies = OrderedDict({'no': 'localhost'}) def send( self, request, stream=False, timeout=None, verify=True, cert=None, proxies=None ): """Sends PreparedRequest object. Returns Response object. :param request: The :class:`PreparedRequest ` being sent. :param stream: (optional) Whether to stream the request content. :param timeout: (optional) How long to wait for the server to send data before giving up, as a float, or a :ref:`(connect timeout, read timeout) ` tuple. :type timeout: float or tuple or urllib3 Timeout object :param verify: (optional) Either a boolean, in which case it controls whether we verify the server's TLS certificate, or a string, in which case it must be a path to a CA bundle to use :param cert: (optional) Any user-provided SSL certificate to be trusted. :param proxies: (optional) The proxies dictionary to apply to the request. :rtype: requests.Response """ try: conn = self.get_connection(request.url, proxies) except LocationValueError as e: raise InvalidURL(e, request=request) self.cert_verify(conn, request.url, verify, cert) url = self.request_url(request, proxies) self.add_headers( request, stream=stream, timeout=timeout, verify=verify, cert=cert, proxies=proxies, ) chunked = not (request.body is None or "Content-Length" in request.headers) if isinstance(timeout, tuple): try: connect, read = timeout timeout = TimeoutSauce(connect=connect, read=read) except ValueError: raise ValueError( f"Invalid timeout {timeout}. Pass a (connect, read) timeout tuple, " f"or a single float to set both timeouts to the same value." ) elif isinstance(timeout, TimeoutSauce): pass else: timeout = TimeoutSauce(connect=timeout, read=timeout) try: resp = conn.urlopen( method=request.method, url=url, body=request.body, headers=request.headers, redirect=False, assert_same_host=False, preload_content=False, decode_content=False, retries=self.max_retries, timeout=timeout, chunked=chunked, ) except (ProtocolError, OSError) as err: raise ConnectionError(err, request=request) except MaxRetryError as e: if isinstance(e.reason, ConnectTimeoutError): # TODO: Remove this in 3.0.0: see #2811 if not isinstance(e.reason, NewConnectionError): raise ConnectTimeout(e, request=request) if isinstance(e.reason, ResponseError): raise RetryError(e, request=request) if isinstance(e.reason, _ProxyError): raise ProxyError(e, request=request) if isinstance(e.reason, _SSLError): # This branch is for urllib3 v1.22 and later. raise SSLError(e, request=request) > raise ConnectionError(e, request=request) E requests.exceptions.ConnectionError: HTTPSConnectionPool(host='raw.githubusercontent.com', port=443): Max retries exceeded with url: /locustio/locust/master/examples/basic.py (Caused by NewConnectionError(': Failed to establish a new connection: [Errno -3] Temporary failure in name resolution')) /usr/lib/python3/dist-packages/requests/adapters.py:519: ConnectionError During handling of the above exception, another exception occurred: self = def test_locustfile_from_url(self): > locustfiles = parse_locustfile_option( args=[ "-f", "https://raw.githubusercontent.com/locustio/locust/master/examples/basic.py", ] ) locust/test/test_load_locustfile.py:216: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ locust/argument_parser.py:370: in parse_locustfile_option download_locustfile_from_url(f) if is_url(f.strip()) else f.strip() for f in options.locustfile.split(",") _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ url = 'https://raw.githubusercontent.com/locustio/locust/master/examples/basic.py' def download_locustfile_from_url(url: str) -> str: try: response = requests.get(url) # Check if response is valid python code ast.parse(response.text) except requests.exceptions.RequestException as e: sys.stderr.write(f"Failed to get locustfile from: {url}. Exception: {e}") > sys.exit(1) E SystemExit: 1 locust/argument_parser.py:198: SystemExit ----------------------------- Captured stderr call ----------------------------- Failed to get locustfile from: https://raw.githubusercontent.com/locustio/locust/master/examples/basic.py. Exception: HTTPSConnectionPool(host='raw.githubusercontent.com', port=443): Max retries exceeded with url: /locustio/locust/master/examples/basic.py (Caused by NewConnectionError(': Failed to establish a new connection: [Errno -3] Temporary failure in name resolution')) _____________________ TestLoggingOptions.test_log_to_file ______________________ self = def test_log_to_file(self): with temporary_file( textwrap.dedent( """ import logging from locust import User, task, constant class MyUser(User): wait_time = constant(2) @task def my_task(self): print("running my_task") logging.info("custom log message") """ ) ) as file_path: with temporary_file("", suffix=".log") as log_file_path: try: > output = subprocess.check_output( [ "locust", "-f", file_path, "-u", "1", "-r", "1", "-t", "1", "--headless", "--logfile", log_file_path, ], stderr=subprocess.STDOUT, timeout=10, text=True, ) locust/test/test_log.py:158: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3/dist-packages/gevent/subprocess.py:405: in check_output with Popen(*popenargs, stdout=PIPE, **kwargs) as process: /usr/lib/python3/dist-packages/gevent/subprocess.py:808: in __init__ self._execute_child(args, executable, preexec_fn, close_fds, _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = args = ['locust', '-f', '/tmp/tmpm2miutke_locustfile.py', '-u', '1', '-r', ...] executable = 'locust', preexec_fn = None, close_fds = True, pass_fds = () cwd = None, env = None, universal_newlines = None, startupinfo = None creationflags = 0, shell = False, p2cread = -1, p2cwrite = -1, c2pread = 11 c2pwrite = 80, errread = -1, errwrite = 80, restore_signals = True, gid = None gids = None, uid = None, umask = -1, start_new_session = False process_group = None def _execute_child(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, universal_newlines, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, restore_signals, gid, gids, uid, umask, start_new_session, process_group): """Execute program (POSIX version)""" if isinstance(args, (str, bytes)): args = [args] elif isinstance(args, PathLike): if shell: raise TypeError('path-like args is not allowed when ' 'shell is true') args = [fsencode(args)] # os.PathLike -> [str] else: args = list(args) if shell: # On Android the default shell is at '/system/bin/sh'. unix_shell = ( '/system/bin/sh' if hasattr(sys, 'getandroidapilevel') else '/bin/sh' ) args = [unix_shell, "-c"] + args if executable: args[0] = executable if executable is None: executable = args[0] self._loop.install_sigchld() # For transferring possible exec failure from child to parent # The first char specifies the exception type: 0 means # OSError, 1 means some other error. errpipe_read, errpipe_write = self.pipe_cloexec() # errpipe_write must not be in the standard io 0, 1, or 2 fd range. low_fds_to_close = [] while errpipe_write < 3: low_fds_to_close.append(errpipe_write) errpipe_write = os.dup(errpipe_write) for low_fd in low_fds_to_close: os.close(low_fd) try: try: gc_was_enabled = gc.isenabled() # Disable gc to avoid bug where gc -> file_dealloc -> # write to stderr -> hang. http://bugs.python.org/issue1336 gc.disable() try: self.pid = fork_and_watch(self._on_child, self._loop, True, fork) except: if gc_was_enabled: gc.enable() raise if self.pid == 0: # Child # In various places on the child side of things, we catch OSError # and add attributes to it that detail where in the process we failed; # like all exceptions until we have exec'd, this exception is pickled # and sent to the parent to raise in the calling process. # The parent uses this to decide how to treat that exception, # adjusting certain information about it as needed. # # Python 3.11.8 --- yes, a minor patch release --- stopped # letting the 'filename' parameter get set in the resulting # exception for many cases. We're not quite interpreting this # the same way the stdlib is, I'm sure, but this makes the stdlib # tests pass. # XXX: Technically we're doing a lot of stuff here that # may not be safe to do before a exec(), depending on the OS. # CPython 3 goes to great lengths to precompute a lot # of this info before the fork and pass it all to C functions that # try hard not to call things like malloc(). (Of course, # CPython 2 pretty much did what we're doing.) try: # Close parent's pipe ends if p2cwrite != -1: os.close(p2cwrite) if c2pread != -1: os.close(c2pread) if errread != -1: os.close(errread) os.close(errpipe_read) # When duping fds, if there arises a situation # where one of the fds is either 0, 1 or 2, it # is possible that it is overwritten (#12607). if c2pwrite == 0: c2pwrite = os.dup(c2pwrite) _set_inheritable(c2pwrite, False) while errwrite in (0, 1): errwrite = os.dup(errwrite) _set_inheritable(errwrite, False) # Dup fds for child def _dup2(existing, desired): # dup2() removes the CLOEXEC flag but # we must do it ourselves if dup2() # would be a no-op (issue #10806). if existing == desired: self._set_cloexec_flag(existing, False) elif existing != -1: os.dup2(existing, desired) try: self._remove_nonblock_flag(desired) except OSError: # Ignore EBADF, it may not actually be # open yet. # Tested beginning in 3.7.0b3 test_subprocess.py pass _dup2(p2cread, 0) _dup2(c2pwrite, 1) _dup2(errwrite, 2) # Close pipe fds. Make sure we don't close the # same fd more than once, or standard fds. if not True: closed = set([None]) for fd in (p2cread, c2pwrite, errwrite): if fd not in closed and fd > 2: os.close(fd) closed.add(fd) # Python 3 (with a working set_inheritable): # We no longer manually close p2cread, # c2pwrite, and errwrite here as # _close_open_fds takes care when it is # not already non-inheritable. if cwd is not None: try: os.chdir(cwd) except OSError as e: e._failed_chdir = True raise # Python 3.9 if umask >= 0: os.umask(umask) # XXX: CPython does _Py_RestoreSignals here. # Then setsid() based on ??? try: if gids: os.setgroups(gids) if gid: os.setregid(gid, gid) if uid: os.setreuid(uid, uid) if process_group is not None: os.setpgid(0, process_group) except OSError as e: e._failed_chuser = True raise if preexec_fn: preexec_fn() # Close all other fds, if asked for. This must be done # after preexec_fn runs. if close_fds: fds_to_keep = set(pass_fds) fds_to_keep.add(errpipe_write) self._close_fds(fds_to_keep, errpipe_write) if restore_signals: # restore the documented signals back to sig_dfl; # not all will be defined on every platform for sig in 'SIGPIPE', 'SIGXFZ', 'SIGXFSZ': sig = getattr(signal, sig, None) if sig is not None: signal.signal(sig, signal.SIG_DFL) if start_new_session: os.setsid() try: if env is None: os.execvp(executable, args) else: # Python 3.6 started testing for # bytes values in the env; it also # started encoding strs using # fsencode and using a lower-level # API that takes a list of keys # and values. We don't have access # to that API, so we go the reverse direction. env = {os.fsdecode(k) if isinstance(k, bytes) else k: os.fsdecode(v) if isinstance(v, bytes) else v for k, v in env.items()} os.execvpe(executable, args, env) except OSError as e: e._failed_exec = True raise except: exc_type, exc_value, tb = sys.exc_info() # Save the traceback and attach it to the exception object exc_lines = traceback.format_exception(exc_type, exc_value, tb) exc_value.child_traceback = ''.join(exc_lines) os.write(errpipe_write, pickle.dumps(exc_value)) finally: # Make sure that the process exits no matter what. # The return code does not matter much as it won't be # reported to the application os._exit(1) # Parent self._child_created = True if gc_was_enabled: gc.enable() finally: # be sure the FD is closed no matter what os.close(errpipe_write) # self._devnull is not always defined. devnull_fd = getattr(self, '_devnull', None) if p2cread != -1 and p2cwrite != -1 and p2cread != devnull_fd: os.close(p2cread) if c2pwrite != -1 and c2pread != -1 and c2pwrite != devnull_fd: os.close(c2pwrite) if errwrite != -1 and errread != -1 and errwrite != devnull_fd: os.close(errwrite) if devnull_fd is not None: os.close(devnull_fd) # Prevent a double close of these fds from __init__ on error. self._closed_child_pipe_fds = True # Wait for exec to fail or succeed; possibly raising exception errpipe_read = FileObject(errpipe_read, 'rb') data = errpipe_read.read() finally: try: if hasattr(errpipe_read, 'close'): errpipe_read.close() else: os.close(errpipe_read) except OSError: # Especially on PyPy, we sometimes see the above # `os.close(errpipe_read)` raise an OSError. # It's not entirely clear why, but it happens in # InterprocessSignalTests.test_main sometimes, which must mean # we have some sort of race condition. pass finally: errpipe_read = -1 if data != b"": self.wait() child_exception = pickle.loads(data) for fd in (p2cwrite, c2pread, errread): if fd is not None and fd != -1: os.close(fd) if isinstance(child_exception, OSError): child_exception.filename = executable if hasattr(child_exception, '_failed_chdir'): child_exception.filename = cwd if getattr(child_exception, '_failed_chuser', False): child_exception.filename = None > raise child_exception E OSError: [Errno 8] Exec format error: 'locust' /usr/lib/python3/dist-packages/gevent/subprocess.py:1838: OSError ____________________ TestLoggingOptions.test_logging_output ____________________ self = def test_logging_output(self): with temporary_file( textwrap.dedent( """ import logging from locust import User, task, constant custom_logger = logging.getLogger("custom_logger") class MyUser(User): wait_time = constant(2) @task def my_task(self): print("running my_task") logging.info("custom log message") custom_logger.info("test") """ ) ) as file_path: > output = subprocess.check_output( [ "locust", "-f", file_path, "-u", "1", "-r", "1", "-t", "1", "--headless", ], stderr=subprocess.STDOUT, timeout=10, text=True, ) locust/test/test_log.py:58: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3/dist-packages/gevent/subprocess.py:405: in check_output with Popen(*popenargs, stdout=PIPE, **kwargs) as process: /usr/lib/python3/dist-packages/gevent/subprocess.py:808: in __init__ self._execute_child(args, executable, preexec_fn, close_fds, _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = args = ['locust', '-f', '/tmp/tmpdocw8f1q_locustfile.py', '-u', '1', '-r', ...] executable = 'locust', preexec_fn = None, close_fds = True, pass_fds = () cwd = None, env = None, universal_newlines = None, startupinfo = None creationflags = 0, shell = False, p2cread = -1, p2cwrite = -1, c2pread = 11 c2pwrite = 80, errread = -1, errwrite = 80, restore_signals = True, gid = None gids = None, uid = None, umask = -1, start_new_session = False process_group = None def _execute_child(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, universal_newlines, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, restore_signals, gid, gids, uid, umask, start_new_session, process_group): """Execute program (POSIX version)""" if isinstance(args, (str, bytes)): args = [args] elif isinstance(args, PathLike): if shell: raise TypeError('path-like args is not allowed when ' 'shell is true') args = [fsencode(args)] # os.PathLike -> [str] else: args = list(args) if shell: # On Android the default shell is at '/system/bin/sh'. unix_shell = ( '/system/bin/sh' if hasattr(sys, 'getandroidapilevel') else '/bin/sh' ) args = [unix_shell, "-c"] + args if executable: args[0] = executable if executable is None: executable = args[0] self._loop.install_sigchld() # For transferring possible exec failure from child to parent # The first char specifies the exception type: 0 means # OSError, 1 means some other error. errpipe_read, errpipe_write = self.pipe_cloexec() # errpipe_write must not be in the standard io 0, 1, or 2 fd range. low_fds_to_close = [] while errpipe_write < 3: low_fds_to_close.append(errpipe_write) errpipe_write = os.dup(errpipe_write) for low_fd in low_fds_to_close: os.close(low_fd) try: try: gc_was_enabled = gc.isenabled() # Disable gc to avoid bug where gc -> file_dealloc -> # write to stderr -> hang. http://bugs.python.org/issue1336 gc.disable() try: self.pid = fork_and_watch(self._on_child, self._loop, True, fork) except: if gc_was_enabled: gc.enable() raise if self.pid == 0: # Child # In various places on the child side of things, we catch OSError # and add attributes to it that detail where in the process we failed; # like all exceptions until we have exec'd, this exception is pickled # and sent to the parent to raise in the calling process. # The parent uses this to decide how to treat that exception, # adjusting certain information about it as needed. # # Python 3.11.8 --- yes, a minor patch release --- stopped # letting the 'filename' parameter get set in the resulting # exception for many cases. We're not quite interpreting this # the same way the stdlib is, I'm sure, but this makes the stdlib # tests pass. # XXX: Technically we're doing a lot of stuff here that # may not be safe to do before a exec(), depending on the OS. # CPython 3 goes to great lengths to precompute a lot # of this info before the fork and pass it all to C functions that # try hard not to call things like malloc(). (Of course, # CPython 2 pretty much did what we're doing.) try: # Close parent's pipe ends if p2cwrite != -1: os.close(p2cwrite) if c2pread != -1: os.close(c2pread) if errread != -1: os.close(errread) os.close(errpipe_read) # When duping fds, if there arises a situation # where one of the fds is either 0, 1 or 2, it # is possible that it is overwritten (#12607). if c2pwrite == 0: c2pwrite = os.dup(c2pwrite) _set_inheritable(c2pwrite, False) while errwrite in (0, 1): errwrite = os.dup(errwrite) _set_inheritable(errwrite, False) # Dup fds for child def _dup2(existing, desired): # dup2() removes the CLOEXEC flag but # we must do it ourselves if dup2() # would be a no-op (issue #10806). if existing == desired: self._set_cloexec_flag(existing, False) elif existing != -1: os.dup2(existing, desired) try: self._remove_nonblock_flag(desired) except OSError: # Ignore EBADF, it may not actually be # open yet. # Tested beginning in 3.7.0b3 test_subprocess.py pass _dup2(p2cread, 0) _dup2(c2pwrite, 1) _dup2(errwrite, 2) # Close pipe fds. Make sure we don't close the # same fd more than once, or standard fds. if not True: closed = set([None]) for fd in (p2cread, c2pwrite, errwrite): if fd not in closed and fd > 2: os.close(fd) closed.add(fd) # Python 3 (with a working set_inheritable): # We no longer manually close p2cread, # c2pwrite, and errwrite here as # _close_open_fds takes care when it is # not already non-inheritable. if cwd is not None: try: os.chdir(cwd) except OSError as e: e._failed_chdir = True raise # Python 3.9 if umask >= 0: os.umask(umask) # XXX: CPython does _Py_RestoreSignals here. # Then setsid() based on ??? try: if gids: os.setgroups(gids) if gid: os.setregid(gid, gid) if uid: os.setreuid(uid, uid) if process_group is not None: os.setpgid(0, process_group) except OSError as e: e._failed_chuser = True raise if preexec_fn: preexec_fn() # Close all other fds, if asked for. This must be done # after preexec_fn runs. if close_fds: fds_to_keep = set(pass_fds) fds_to_keep.add(errpipe_write) self._close_fds(fds_to_keep, errpipe_write) if restore_signals: # restore the documented signals back to sig_dfl; # not all will be defined on every platform for sig in 'SIGPIPE', 'SIGXFZ', 'SIGXFSZ': sig = getattr(signal, sig, None) if sig is not None: signal.signal(sig, signal.SIG_DFL) if start_new_session: os.setsid() try: if env is None: os.execvp(executable, args) else: # Python 3.6 started testing for # bytes values in the env; it also # started encoding strs using # fsencode and using a lower-level # API that takes a list of keys # and values. We don't have access # to that API, so we go the reverse direction. env = {os.fsdecode(k) if isinstance(k, bytes) else k: os.fsdecode(v) if isinstance(v, bytes) else v for k, v in env.items()} os.execvpe(executable, args, env) except OSError as e: e._failed_exec = True raise except: exc_type, exc_value, tb = sys.exc_info() # Save the traceback and attach it to the exception object exc_lines = traceback.format_exception(exc_type, exc_value, tb) exc_value.child_traceback = ''.join(exc_lines) os.write(errpipe_write, pickle.dumps(exc_value)) finally: # Make sure that the process exits no matter what. # The return code does not matter much as it won't be # reported to the application os._exit(1) # Parent self._child_created = True if gc_was_enabled: gc.enable() finally: # be sure the FD is closed no matter what os.close(errpipe_write) # self._devnull is not always defined. devnull_fd = getattr(self, '_devnull', None) if p2cread != -1 and p2cwrite != -1 and p2cread != devnull_fd: os.close(p2cread) if c2pwrite != -1 and c2pread != -1 and c2pwrite != devnull_fd: os.close(c2pwrite) if errwrite != -1 and errread != -1 and errwrite != devnull_fd: os.close(errwrite) if devnull_fd is not None: os.close(devnull_fd) # Prevent a double close of these fds from __init__ on error. self._closed_child_pipe_fds = True # Wait for exec to fail or succeed; possibly raising exception errpipe_read = FileObject(errpipe_read, 'rb') data = errpipe_read.read() finally: try: if hasattr(errpipe_read, 'close'): errpipe_read.close() else: os.close(errpipe_read) except OSError: # Especially on PyPy, we sometimes see the above # `os.close(errpipe_read)` raise an OSError. # It's not entirely clear why, but it happens in # InterprocessSignalTests.test_main sometimes, which must mean # we have some sort of race condition. pass finally: errpipe_read = -1 if data != b"": self.wait() child_exception = pickle.loads(data) for fd in (p2cwrite, c2pread, errread): if fd is not None and fd != -1: os.close(fd) if isinstance(child_exception, OSError): child_exception.filename = executable if hasattr(child_exception, '_failed_chdir'): child_exception.filename = cwd if getattr(child_exception, '_failed_chuser', False): child_exception.filename = None > raise child_exception E OSError: [Errno 8] Exec format error: 'locust' /usr/lib/python3/dist-packages/gevent/subprocess.py:1838: OSError _____________________ TestLoggingOptions.test_skip_logging _____________________ self = def test_skip_logging(self): with temporary_file( textwrap.dedent( """ from locust import User, task, constant class MyUser(User): wait_time = constant(2) @task def my_task(self): print("running my_task") """ ) ) as file_path: > output = subprocess.check_output( [ "locust", "-f", file_path, "-u", "1", "-r", "1", "-t", "1", "--headless", "--skip-log-setup", ], stderr=subprocess.STDOUT, timeout=10, text=True, ) locust/test/test_log.py:117: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3/dist-packages/gevent/subprocess.py:405: in check_output with Popen(*popenargs, stdout=PIPE, **kwargs) as process: /usr/lib/python3/dist-packages/gevent/subprocess.py:808: in __init__ self._execute_child(args, executable, preexec_fn, close_fds, _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = args = ['locust', '-f', '/tmp/tmpojjvshpx_locustfile.py', '-u', '1', '-r', ...] executable = 'locust', preexec_fn = None, close_fds = True, pass_fds = () cwd = None, env = None, universal_newlines = None, startupinfo = None creationflags = 0, shell = False, p2cread = -1, p2cwrite = -1, c2pread = 11 c2pwrite = 80, errread = -1, errwrite = 80, restore_signals = True, gid = None gids = None, uid = None, umask = -1, start_new_session = False process_group = None def _execute_child(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, universal_newlines, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, restore_signals, gid, gids, uid, umask, start_new_session, process_group): """Execute program (POSIX version)""" if isinstance(args, (str, bytes)): args = [args] elif isinstance(args, PathLike): if shell: raise TypeError('path-like args is not allowed when ' 'shell is true') args = [fsencode(args)] # os.PathLike -> [str] else: args = list(args) if shell: # On Android the default shell is at '/system/bin/sh'. unix_shell = ( '/system/bin/sh' if hasattr(sys, 'getandroidapilevel') else '/bin/sh' ) args = [unix_shell, "-c"] + args if executable: args[0] = executable if executable is None: executable = args[0] self._loop.install_sigchld() # For transferring possible exec failure from child to parent # The first char specifies the exception type: 0 means # OSError, 1 means some other error. errpipe_read, errpipe_write = self.pipe_cloexec() # errpipe_write must not be in the standard io 0, 1, or 2 fd range. low_fds_to_close = [] while errpipe_write < 3: low_fds_to_close.append(errpipe_write) errpipe_write = os.dup(errpipe_write) for low_fd in low_fds_to_close: os.close(low_fd) try: try: gc_was_enabled = gc.isenabled() # Disable gc to avoid bug where gc -> file_dealloc -> # write to stderr -> hang. http://bugs.python.org/issue1336 gc.disable() try: self.pid = fork_and_watch(self._on_child, self._loop, True, fork) except: if gc_was_enabled: gc.enable() raise if self.pid == 0: # Child # In various places on the child side of things, we catch OSError # and add attributes to it that detail where in the process we failed; # like all exceptions until we have exec'd, this exception is pickled # and sent to the parent to raise in the calling process. # The parent uses this to decide how to treat that exception, # adjusting certain information about it as needed. # # Python 3.11.8 --- yes, a minor patch release --- stopped # letting the 'filename' parameter get set in the resulting # exception for many cases. We're not quite interpreting this # the same way the stdlib is, I'm sure, but this makes the stdlib # tests pass. # XXX: Technically we're doing a lot of stuff here that # may not be safe to do before a exec(), depending on the OS. # CPython 3 goes to great lengths to precompute a lot # of this info before the fork and pass it all to C functions that # try hard not to call things like malloc(). (Of course, # CPython 2 pretty much did what we're doing.) try: # Close parent's pipe ends if p2cwrite != -1: os.close(p2cwrite) if c2pread != -1: os.close(c2pread) if errread != -1: os.close(errread) os.close(errpipe_read) # When duping fds, if there arises a situation # where one of the fds is either 0, 1 or 2, it # is possible that it is overwritten (#12607). if c2pwrite == 0: c2pwrite = os.dup(c2pwrite) _set_inheritable(c2pwrite, False) while errwrite in (0, 1): errwrite = os.dup(errwrite) _set_inheritable(errwrite, False) # Dup fds for child def _dup2(existing, desired): # dup2() removes the CLOEXEC flag but # we must do it ourselves if dup2() # would be a no-op (issue #10806). if existing == desired: self._set_cloexec_flag(existing, False) elif existing != -1: os.dup2(existing, desired) try: self._remove_nonblock_flag(desired) except OSError: # Ignore EBADF, it may not actually be # open yet. # Tested beginning in 3.7.0b3 test_subprocess.py pass _dup2(p2cread, 0) _dup2(c2pwrite, 1) _dup2(errwrite, 2) # Close pipe fds. Make sure we don't close the # same fd more than once, or standard fds. if not True: closed = set([None]) for fd in (p2cread, c2pwrite, errwrite): if fd not in closed and fd > 2: os.close(fd) closed.add(fd) # Python 3 (with a working set_inheritable): # We no longer manually close p2cread, # c2pwrite, and errwrite here as # _close_open_fds takes care when it is # not already non-inheritable. if cwd is not None: try: os.chdir(cwd) except OSError as e: e._failed_chdir = True raise # Python 3.9 if umask >= 0: os.umask(umask) # XXX: CPython does _Py_RestoreSignals here. # Then setsid() based on ??? try: if gids: os.setgroups(gids) if gid: os.setregid(gid, gid) if uid: os.setreuid(uid, uid) if process_group is not None: os.setpgid(0, process_group) except OSError as e: e._failed_chuser = True raise if preexec_fn: preexec_fn() # Close all other fds, if asked for. This must be done # after preexec_fn runs. if close_fds: fds_to_keep = set(pass_fds) fds_to_keep.add(errpipe_write) self._close_fds(fds_to_keep, errpipe_write) if restore_signals: # restore the documented signals back to sig_dfl; # not all will be defined on every platform for sig in 'SIGPIPE', 'SIGXFZ', 'SIGXFSZ': sig = getattr(signal, sig, None) if sig is not None: signal.signal(sig, signal.SIG_DFL) if start_new_session: os.setsid() try: if env is None: os.execvp(executable, args) else: # Python 3.6 started testing for # bytes values in the env; it also # started encoding strs using # fsencode and using a lower-level # API that takes a list of keys # and values. We don't have access # to that API, so we go the reverse direction. env = {os.fsdecode(k) if isinstance(k, bytes) else k: os.fsdecode(v) if isinstance(v, bytes) else v for k, v in env.items()} os.execvpe(executable, args, env) except OSError as e: e._failed_exec = True raise except: exc_type, exc_value, tb = sys.exc_info() # Save the traceback and attach it to the exception object exc_lines = traceback.format_exception(exc_type, exc_value, tb) exc_value.child_traceback = ''.join(exc_lines) os.write(errpipe_write, pickle.dumps(exc_value)) finally: # Make sure that the process exits no matter what. # The return code does not matter much as it won't be # reported to the application os._exit(1) # Parent self._child_created = True if gc_was_enabled: gc.enable() finally: # be sure the FD is closed no matter what os.close(errpipe_write) # self._devnull is not always defined. devnull_fd = getattr(self, '_devnull', None) if p2cread != -1 and p2cwrite != -1 and p2cread != devnull_fd: os.close(p2cread) if c2pwrite != -1 and c2pread != -1 and c2pwrite != devnull_fd: os.close(c2pwrite) if errwrite != -1 and errread != -1 and errwrite != devnull_fd: os.close(errwrite) if devnull_fd is not None: os.close(devnull_fd) # Prevent a double close of these fds from __init__ on error. self._closed_child_pipe_fds = True # Wait for exec to fail or succeed; possibly raising exception errpipe_read = FileObject(errpipe_read, 'rb') data = errpipe_read.read() finally: try: if hasattr(errpipe_read, 'close'): errpipe_read.close() else: os.close(errpipe_read) except OSError: # Especially on PyPy, we sometimes see the above # `os.close(errpipe_read)` raise an OSError. # It's not entirely clear why, but it happens in # InterprocessSignalTests.test_main sometimes, which must mean # we have some sort of race condition. pass finally: errpipe_read = -1 if data != b"": self.wait() child_exception = pickle.loads(data) for fd in (p2cwrite, c2pread, errread): if fd is not None and fd != -1: os.close(fd) if isinstance(child_exception, OSError): child_exception.filename = executable if hasattr(child_exception, '_failed_chdir'): child_exception.filename = cwd if getattr(child_exception, '_failed_chuser', False): child_exception.filename = None > raise child_exception E OSError: [Errno 8] Exec format error: 'locust' /usr/lib/python3/dist-packages/gevent/subprocess.py:1838: OSError _________________ TestLoggingOptions.test_user_broken_on_start _________________ self = def test_user_broken_on_start(self): with temporary_file( textwrap.dedent( """ from locust import HttpUser, task class TestUser(HttpUser): host = "invalidhost" def on_start(self): self.client.get("/") """ ) ) as file_path: > output = subprocess.check_output( [ "locust", "-f", file_path, "-t", "1", "--headless", ], stderr=subprocess.STDOUT, timeout=10, text=True, ) locust/test/test_log.py:223: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3/dist-packages/gevent/subprocess.py:405: in check_output with Popen(*popenargs, stdout=PIPE, **kwargs) as process: /usr/lib/python3/dist-packages/gevent/subprocess.py:808: in __init__ self._execute_child(args, executable, preexec_fn, close_fds, _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = args = ['locust', '-f', '/tmp/tmpeg7uoqjg_locustfile.py', '-t', '1', '--headless'] executable = 'locust', preexec_fn = None, close_fds = True, pass_fds = () cwd = None, env = None, universal_newlines = None, startupinfo = None creationflags = 0, shell = False, p2cread = -1, p2cwrite = -1, c2pread = 11 c2pwrite = 80, errread = -1, errwrite = 80, restore_signals = True, gid = None gids = None, uid = None, umask = -1, start_new_session = False process_group = None def _execute_child(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, universal_newlines, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, restore_signals, gid, gids, uid, umask, start_new_session, process_group): """Execute program (POSIX version)""" if isinstance(args, (str, bytes)): args = [args] elif isinstance(args, PathLike): if shell: raise TypeError('path-like args is not allowed when ' 'shell is true') args = [fsencode(args)] # os.PathLike -> [str] else: args = list(args) if shell: # On Android the default shell is at '/system/bin/sh'. unix_shell = ( '/system/bin/sh' if hasattr(sys, 'getandroidapilevel') else '/bin/sh' ) args = [unix_shell, "-c"] + args if executable: args[0] = executable if executable is None: executable = args[0] self._loop.install_sigchld() # For transferring possible exec failure from child to parent # The first char specifies the exception type: 0 means # OSError, 1 means some other error. errpipe_read, errpipe_write = self.pipe_cloexec() # errpipe_write must not be in the standard io 0, 1, or 2 fd range. low_fds_to_close = [] while errpipe_write < 3: low_fds_to_close.append(errpipe_write) errpipe_write = os.dup(errpipe_write) for low_fd in low_fds_to_close: os.close(low_fd) try: try: gc_was_enabled = gc.isenabled() # Disable gc to avoid bug where gc -> file_dealloc -> # write to stderr -> hang. http://bugs.python.org/issue1336 gc.disable() try: self.pid = fork_and_watch(self._on_child, self._loop, True, fork) except: if gc_was_enabled: gc.enable() raise if self.pid == 0: # Child # In various places on the child side of things, we catch OSError # and add attributes to it that detail where in the process we failed; # like all exceptions until we have exec'd, this exception is pickled # and sent to the parent to raise in the calling process. # The parent uses this to decide how to treat that exception, # adjusting certain information about it as needed. # # Python 3.11.8 --- yes, a minor patch release --- stopped # letting the 'filename' parameter get set in the resulting # exception for many cases. We're not quite interpreting this # the same way the stdlib is, I'm sure, but this makes the stdlib # tests pass. # XXX: Technically we're doing a lot of stuff here that # may not be safe to do before a exec(), depending on the OS. # CPython 3 goes to great lengths to precompute a lot # of this info before the fork and pass it all to C functions that # try hard not to call things like malloc(). (Of course, # CPython 2 pretty much did what we're doing.) try: # Close parent's pipe ends if p2cwrite != -1: os.close(p2cwrite) if c2pread != -1: os.close(c2pread) if errread != -1: os.close(errread) os.close(errpipe_read) # When duping fds, if there arises a situation # where one of the fds is either 0, 1 or 2, it # is possible that it is overwritten (#12607). if c2pwrite == 0: c2pwrite = os.dup(c2pwrite) _set_inheritable(c2pwrite, False) while errwrite in (0, 1): errwrite = os.dup(errwrite) _set_inheritable(errwrite, False) # Dup fds for child def _dup2(existing, desired): # dup2() removes the CLOEXEC flag but # we must do it ourselves if dup2() # would be a no-op (issue #10806). if existing == desired: self._set_cloexec_flag(existing, False) elif existing != -1: os.dup2(existing, desired) try: self._remove_nonblock_flag(desired) except OSError: # Ignore EBADF, it may not actually be # open yet. # Tested beginning in 3.7.0b3 test_subprocess.py pass _dup2(p2cread, 0) _dup2(c2pwrite, 1) _dup2(errwrite, 2) # Close pipe fds. Make sure we don't close the # same fd more than once, or standard fds. if not True: closed = set([None]) for fd in (p2cread, c2pwrite, errwrite): if fd not in closed and fd > 2: os.close(fd) closed.add(fd) # Python 3 (with a working set_inheritable): # We no longer manually close p2cread, # c2pwrite, and errwrite here as # _close_open_fds takes care when it is # not already non-inheritable. if cwd is not None: try: os.chdir(cwd) except OSError as e: e._failed_chdir = True raise # Python 3.9 if umask >= 0: os.umask(umask) # XXX: CPython does _Py_RestoreSignals here. # Then setsid() based on ??? try: if gids: os.setgroups(gids) if gid: os.setregid(gid, gid) if uid: os.setreuid(uid, uid) if process_group is not None: os.setpgid(0, process_group) except OSError as e: e._failed_chuser = True raise if preexec_fn: preexec_fn() # Close all other fds, if asked for. This must be done # after preexec_fn runs. if close_fds: fds_to_keep = set(pass_fds) fds_to_keep.add(errpipe_write) self._close_fds(fds_to_keep, errpipe_write) if restore_signals: # restore the documented signals back to sig_dfl; # not all will be defined on every platform for sig in 'SIGPIPE', 'SIGXFZ', 'SIGXFSZ': sig = getattr(signal, sig, None) if sig is not None: signal.signal(sig, signal.SIG_DFL) if start_new_session: os.setsid() try: if env is None: os.execvp(executable, args) else: # Python 3.6 started testing for # bytes values in the env; it also # started encoding strs using # fsencode and using a lower-level # API that takes a list of keys # and values. We don't have access # to that API, so we go the reverse direction. env = {os.fsdecode(k) if isinstance(k, bytes) else k: os.fsdecode(v) if isinstance(v, bytes) else v for k, v in env.items()} os.execvpe(executable, args, env) except OSError as e: e._failed_exec = True raise except: exc_type, exc_value, tb = sys.exc_info() # Save the traceback and attach it to the exception object exc_lines = traceback.format_exception(exc_type, exc_value, tb) exc_value.child_traceback = ''.join(exc_lines) os.write(errpipe_write, pickle.dumps(exc_value)) finally: # Make sure that the process exits no matter what. # The return code does not matter much as it won't be # reported to the application os._exit(1) # Parent self._child_created = True if gc_was_enabled: gc.enable() finally: # be sure the FD is closed no matter what os.close(errpipe_write) # self._devnull is not always defined. devnull_fd = getattr(self, '_devnull', None) if p2cread != -1 and p2cwrite != -1 and p2cread != devnull_fd: os.close(p2cread) if c2pwrite != -1 and c2pread != -1 and c2pwrite != devnull_fd: os.close(c2pwrite) if errwrite != -1 and errread != -1 and errwrite != devnull_fd: os.close(errwrite) if devnull_fd is not None: os.close(devnull_fd) # Prevent a double close of these fds from __init__ on error. self._closed_child_pipe_fds = True # Wait for exec to fail or succeed; possibly raising exception errpipe_read = FileObject(errpipe_read, 'rb') data = errpipe_read.read() finally: try: if hasattr(errpipe_read, 'close'): errpipe_read.close() else: os.close(errpipe_read) except OSError: # Especially on PyPy, we sometimes see the above # `os.close(errpipe_read)` raise an OSError. # It's not entirely clear why, but it happens in # InterprocessSignalTests.test_main sometimes, which must mean # we have some sort of race condition. pass finally: errpipe_read = -1 if data != b"": self.wait() child_exception = pickle.loads(data) for fd in (p2cwrite, c2pread, errread): if fd is not None and fd != -1: os.close(fd) if isinstance(child_exception, OSError): child_exception.filename = executable if hasattr(child_exception, '_failed_chdir'): child_exception.filename = cwd if getattr(child_exception, '_failed_chuser', False): child_exception.filename = None > raise child_exception E OSError: [Errno 8] Exec format error: 'locust' /usr/lib/python3/dist-packages/gevent/subprocess.py:1838: OSError __ StandaloneIntegrationTests.test_autostart_multiple_locustfiles_with_shape ___ self = def test_autostart_multiple_locustfiles_with_shape(self): port = get_free_tcp_port() content = textwrap.dedent( """ from locust import User, task, between class TestUser2(User): wait_time = between(2, 4) @task def my_task(self): print("running my_task() again") """ ) with mock_locustfile(content=content) as mocked1: with temporary_file( content=textwrap.dedent( """ from locust import User, task, between, LoadTestShape class LoadTestShape(LoadTestShape): def tick(self): run_time = self.get_run_time() if run_time < 2: return (10, 1) return None class TestUser(User): wait_time = between(2, 4) @task def my_task(self): print("running my_task()") """ ) ) as mocked2: > proc = subprocess.Popen( [ "locust", "-f", f"{mocked1.file_path},{mocked2}", "--legacy-ui", "--web-port", str(port), "--autostart", "--autoquit", "3", ], stdout=PIPE, stderr=PIPE, text=True, ) locust/test/test_main.py:794: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3/dist-packages/gevent/subprocess.py:808: in __init__ self._execute_child(args, executable, preexec_fn, close_fds, _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = args = ['locust', '-f', '/build/reproducible-path/locust-2.24.0/locust/test/mock_locustfile_1715255799_2959747_4425.py,/tmp/tmpz0c81hwv_locustfile.py', '--legacy-ui', '--web-port', '55439', ...] executable = 'locust', preexec_fn = None, close_fds = True, pass_fds = () cwd = None, env = None, universal_newlines = None, startupinfo = None creationflags = 0, shell = False, p2cread = -1, p2cwrite = -1, c2pread = 11 c2pwrite = 80, errread = 81, errwrite = 82, restore_signals = True, gid = None gids = None, uid = None, umask = -1, start_new_session = False process_group = None def _execute_child(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, universal_newlines, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, restore_signals, gid, gids, uid, umask, start_new_session, process_group): """Execute program (POSIX version)""" if isinstance(args, (str, bytes)): args = [args] elif isinstance(args, PathLike): if shell: raise TypeError('path-like args is not allowed when ' 'shell is true') args = [fsencode(args)] # os.PathLike -> [str] else: args = list(args) if shell: # On Android the default shell is at '/system/bin/sh'. unix_shell = ( '/system/bin/sh' if hasattr(sys, 'getandroidapilevel') else '/bin/sh' ) args = [unix_shell, "-c"] + args if executable: args[0] = executable if executable is None: executable = args[0] self._loop.install_sigchld() # For transferring possible exec failure from child to parent # The first char specifies the exception type: 0 means # OSError, 1 means some other error. errpipe_read, errpipe_write = self.pipe_cloexec() # errpipe_write must not be in the standard io 0, 1, or 2 fd range. low_fds_to_close = [] while errpipe_write < 3: low_fds_to_close.append(errpipe_write) errpipe_write = os.dup(errpipe_write) for low_fd in low_fds_to_close: os.close(low_fd) try: try: gc_was_enabled = gc.isenabled() # Disable gc to avoid bug where gc -> file_dealloc -> # write to stderr -> hang. http://bugs.python.org/issue1336 gc.disable() try: self.pid = fork_and_watch(self._on_child, self._loop, True, fork) except: if gc_was_enabled: gc.enable() raise if self.pid == 0: # Child # In various places on the child side of things, we catch OSError # and add attributes to it that detail where in the process we failed; # like all exceptions until we have exec'd, this exception is pickled # and sent to the parent to raise in the calling process. # The parent uses this to decide how to treat that exception, # adjusting certain information about it as needed. # # Python 3.11.8 --- yes, a minor patch release --- stopped # letting the 'filename' parameter get set in the resulting # exception for many cases. We're not quite interpreting this # the same way the stdlib is, I'm sure, but this makes the stdlib # tests pass. # XXX: Technically we're doing a lot of stuff here that # may not be safe to do before a exec(), depending on the OS. # CPython 3 goes to great lengths to precompute a lot # of this info before the fork and pass it all to C functions that # try hard not to call things like malloc(). (Of course, # CPython 2 pretty much did what we're doing.) try: # Close parent's pipe ends if p2cwrite != -1: os.close(p2cwrite) if c2pread != -1: os.close(c2pread) if errread != -1: os.close(errread) os.close(errpipe_read) # When duping fds, if there arises a situation # where one of the fds is either 0, 1 or 2, it # is possible that it is overwritten (#12607). if c2pwrite == 0: c2pwrite = os.dup(c2pwrite) _set_inheritable(c2pwrite, False) while errwrite in (0, 1): errwrite = os.dup(errwrite) _set_inheritable(errwrite, False) # Dup fds for child def _dup2(existing, desired): # dup2() removes the CLOEXEC flag but # we must do it ourselves if dup2() # would be a no-op (issue #10806). if existing == desired: self._set_cloexec_flag(existing, False) elif existing != -1: os.dup2(existing, desired) try: self._remove_nonblock_flag(desired) except OSError: # Ignore EBADF, it may not actually be # open yet. # Tested beginning in 3.7.0b3 test_subprocess.py pass _dup2(p2cread, 0) _dup2(c2pwrite, 1) _dup2(errwrite, 2) # Close pipe fds. Make sure we don't close the # same fd more than once, or standard fds. if not True: closed = set([None]) for fd in (p2cread, c2pwrite, errwrite): if fd not in closed and fd > 2: os.close(fd) closed.add(fd) # Python 3 (with a working set_inheritable): # We no longer manually close p2cread, # c2pwrite, and errwrite here as # _close_open_fds takes care when it is # not already non-inheritable. if cwd is not None: try: os.chdir(cwd) except OSError as e: e._failed_chdir = True raise # Python 3.9 if umask >= 0: os.umask(umask) # XXX: CPython does _Py_RestoreSignals here. # Then setsid() based on ??? try: if gids: os.setgroups(gids) if gid: os.setregid(gid, gid) if uid: os.setreuid(uid, uid) if process_group is not None: os.setpgid(0, process_group) except OSError as e: e._failed_chuser = True raise if preexec_fn: preexec_fn() # Close all other fds, if asked for. This must be done # after preexec_fn runs. if close_fds: fds_to_keep = set(pass_fds) fds_to_keep.add(errpipe_write) self._close_fds(fds_to_keep, errpipe_write) if restore_signals: # restore the documented signals back to sig_dfl; # not all will be defined on every platform for sig in 'SIGPIPE', 'SIGXFZ', 'SIGXFSZ': sig = getattr(signal, sig, None) if sig is not None: signal.signal(sig, signal.SIG_DFL) if start_new_session: os.setsid() try: if env is None: os.execvp(executable, args) else: # Python 3.6 started testing for # bytes values in the env; it also # started encoding strs using # fsencode and using a lower-level # API that takes a list of keys # and values. We don't have access # to that API, so we go the reverse direction. env = {os.fsdecode(k) if isinstance(k, bytes) else k: os.fsdecode(v) if isinstance(v, bytes) else v for k, v in env.items()} os.execvpe(executable, args, env) except OSError as e: e._failed_exec = True raise except: exc_type, exc_value, tb = sys.exc_info() # Save the traceback and attach it to the exception object exc_lines = traceback.format_exception(exc_type, exc_value, tb) exc_value.child_traceback = ''.join(exc_lines) os.write(errpipe_write, pickle.dumps(exc_value)) finally: # Make sure that the process exits no matter what. # The return code does not matter much as it won't be # reported to the application os._exit(1) # Parent self._child_created = True if gc_was_enabled: gc.enable() finally: # be sure the FD is closed no matter what os.close(errpipe_write) # self._devnull is not always defined. devnull_fd = getattr(self, '_devnull', None) if p2cread != -1 and p2cwrite != -1 and p2cread != devnull_fd: os.close(p2cread) if c2pwrite != -1 and c2pread != -1 and c2pwrite != devnull_fd: os.close(c2pwrite) if errwrite != -1 and errread != -1 and errwrite != devnull_fd: os.close(errwrite) if devnull_fd is not None: os.close(devnull_fd) # Prevent a double close of these fds from __init__ on error. self._closed_child_pipe_fds = True # Wait for exec to fail or succeed; possibly raising exception errpipe_read = FileObject(errpipe_read, 'rb') data = errpipe_read.read() finally: try: if hasattr(errpipe_read, 'close'): errpipe_read.close() else: os.close(errpipe_read) except OSError: # Especially on PyPy, we sometimes see the above # `os.close(errpipe_read)` raise an OSError. # It's not entirely clear why, but it happens in # InterprocessSignalTests.test_main sometimes, which must mean # we have some sort of race condition. pass finally: errpipe_read = -1 if data != b"": self.wait() child_exception = pickle.loads(data) for fd in (p2cwrite, c2pread, errread): if fd is not None and fd != -1: os.close(fd) if isinstance(child_exception, OSError): child_exception.filename = executable if hasattr(child_exception, '_failed_chdir'): child_exception.filename = cwd if getattr(child_exception, '_failed_chuser', False): child_exception.filename = None > raise child_exception E OSError: [Errno 8] Exec format error: 'locust' /usr/lib/python3/dist-packages/gevent/subprocess.py:1838: OSError ____________ StandaloneIntegrationTests.test_autostart_w_load_shape ____________ self = def test_autostart_w_load_shape(self): port = get_free_tcp_port() with mock_locustfile( content=MOCK_LOCUSTFILE_CONTENT + textwrap.dedent( """ from locust import LoadTestShape class LoadTestShape(LoadTestShape): def tick(self): run_time = self.get_run_time() if run_time < 2: return (10, 1) return None """ ) ) as mocked: > proc = subprocess.Popen( [ "locust", "-f", mocked.file_path, "--legacy-ui", "--web-port", str(port), "--autostart", "--autoquit", "3", ], stdout=PIPE, stderr=PIPE, text=True, ) locust/test/test_main.py:727: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3/dist-packages/gevent/subprocess.py:808: in __init__ self._execute_child(args, executable, preexec_fn, close_fds, _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = args = ['locust', '-f', '/build/reproducible-path/locust-2.24.0/locust/test/mock_locustfile_1715255799_4797375_38276.py', '--legacy-ui', '--web-port', '53255', ...] executable = 'locust', preexec_fn = None, close_fds = True, pass_fds = () cwd = None, env = None, universal_newlines = None, startupinfo = None creationflags = 0, shell = False, p2cread = -1, p2cwrite = -1, c2pread = 11 c2pwrite = 80, errread = 81, errwrite = 82, restore_signals = True, gid = None gids = None, uid = None, umask = -1, start_new_session = False process_group = None def _execute_child(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, universal_newlines, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, restore_signals, gid, gids, uid, umask, start_new_session, process_group): """Execute program (POSIX version)""" if isinstance(args, (str, bytes)): args = [args] elif isinstance(args, PathLike): if shell: raise TypeError('path-like args is not allowed when ' 'shell is true') args = [fsencode(args)] # os.PathLike -> [str] else: args = list(args) if shell: # On Android the default shell is at '/system/bin/sh'. unix_shell = ( '/system/bin/sh' if hasattr(sys, 'getandroidapilevel') else '/bin/sh' ) args = [unix_shell, "-c"] + args if executable: args[0] = executable if executable is None: executable = args[0] self._loop.install_sigchld() # For transferring possible exec failure from child to parent # The first char specifies the exception type: 0 means # OSError, 1 means some other error. errpipe_read, errpipe_write = self.pipe_cloexec() # errpipe_write must not be in the standard io 0, 1, or 2 fd range. low_fds_to_close = [] while errpipe_write < 3: low_fds_to_close.append(errpipe_write) errpipe_write = os.dup(errpipe_write) for low_fd in low_fds_to_close: os.close(low_fd) try: try: gc_was_enabled = gc.isenabled() # Disable gc to avoid bug where gc -> file_dealloc -> # write to stderr -> hang. http://bugs.python.org/issue1336 gc.disable() try: self.pid = fork_and_watch(self._on_child, self._loop, True, fork) except: if gc_was_enabled: gc.enable() raise if self.pid == 0: # Child # In various places on the child side of things, we catch OSError # and add attributes to it that detail where in the process we failed; # like all exceptions until we have exec'd, this exception is pickled # and sent to the parent to raise in the calling process. # The parent uses this to decide how to treat that exception, # adjusting certain information about it as needed. # # Python 3.11.8 --- yes, a minor patch release --- stopped # letting the 'filename' parameter get set in the resulting # exception for many cases. We're not quite interpreting this # the same way the stdlib is, I'm sure, but this makes the stdlib # tests pass. # XXX: Technically we're doing a lot of stuff here that # may not be safe to do before a exec(), depending on the OS. # CPython 3 goes to great lengths to precompute a lot # of this info before the fork and pass it all to C functions that # try hard not to call things like malloc(). (Of course, # CPython 2 pretty much did what we're doing.) try: # Close parent's pipe ends if p2cwrite != -1: os.close(p2cwrite) if c2pread != -1: os.close(c2pread) if errread != -1: os.close(errread) os.close(errpipe_read) # When duping fds, if there arises a situation # where one of the fds is either 0, 1 or 2, it # is possible that it is overwritten (#12607). if c2pwrite == 0: c2pwrite = os.dup(c2pwrite) _set_inheritable(c2pwrite, False) while errwrite in (0, 1): errwrite = os.dup(errwrite) _set_inheritable(errwrite, False) # Dup fds for child def _dup2(existing, desired): # dup2() removes the CLOEXEC flag but # we must do it ourselves if dup2() # would be a no-op (issue #10806). if existing == desired: self._set_cloexec_flag(existing, False) elif existing != -1: os.dup2(existing, desired) try: self._remove_nonblock_flag(desired) except OSError: # Ignore EBADF, it may not actually be # open yet. # Tested beginning in 3.7.0b3 test_subprocess.py pass _dup2(p2cread, 0) _dup2(c2pwrite, 1) _dup2(errwrite, 2) # Close pipe fds. Make sure we don't close the # same fd more than once, or standard fds. if not True: closed = set([None]) for fd in (p2cread, c2pwrite, errwrite): if fd not in closed and fd > 2: os.close(fd) closed.add(fd) # Python 3 (with a working set_inheritable): # We no longer manually close p2cread, # c2pwrite, and errwrite here as # _close_open_fds takes care when it is # not already non-inheritable. if cwd is not None: try: os.chdir(cwd) except OSError as e: e._failed_chdir = True raise # Python 3.9 if umask >= 0: os.umask(umask) # XXX: CPython does _Py_RestoreSignals here. # Then setsid() based on ??? try: if gids: os.setgroups(gids) if gid: os.setregid(gid, gid) if uid: os.setreuid(uid, uid) if process_group is not None: os.setpgid(0, process_group) except OSError as e: e._failed_chuser = True raise if preexec_fn: preexec_fn() # Close all other fds, if asked for. This must be done # after preexec_fn runs. if close_fds: fds_to_keep = set(pass_fds) fds_to_keep.add(errpipe_write) self._close_fds(fds_to_keep, errpipe_write) if restore_signals: # restore the documented signals back to sig_dfl; # not all will be defined on every platform for sig in 'SIGPIPE', 'SIGXFZ', 'SIGXFSZ': sig = getattr(signal, sig, None) if sig is not None: signal.signal(sig, signal.SIG_DFL) if start_new_session: os.setsid() try: if env is None: os.execvp(executable, args) else: # Python 3.6 started testing for # bytes values in the env; it also # started encoding strs using # fsencode and using a lower-level # API that takes a list of keys # and values. We don't have access # to that API, so we go the reverse direction. env = {os.fsdecode(k) if isinstance(k, bytes) else k: os.fsdecode(v) if isinstance(v, bytes) else v for k, v in env.items()} os.execvpe(executable, args, env) except OSError as e: e._failed_exec = True raise except: exc_type, exc_value, tb = sys.exc_info() # Save the traceback and attach it to the exception object exc_lines = traceback.format_exception(exc_type, exc_value, tb) exc_value.child_traceback = ''.join(exc_lines) os.write(errpipe_write, pickle.dumps(exc_value)) finally: # Make sure that the process exits no matter what. # The return code does not matter much as it won't be # reported to the application os._exit(1) # Parent self._child_created = True if gc_was_enabled: gc.enable() finally: # be sure the FD is closed no matter what os.close(errpipe_write) # self._devnull is not always defined. devnull_fd = getattr(self, '_devnull', None) if p2cread != -1 and p2cwrite != -1 and p2cread != devnull_fd: os.close(p2cread) if c2pwrite != -1 and c2pread != -1 and c2pwrite != devnull_fd: os.close(c2pwrite) if errwrite != -1 and errread != -1 and errwrite != devnull_fd: os.close(errwrite) if devnull_fd is not None: os.close(devnull_fd) # Prevent a double close of these fds from __init__ on error. self._closed_child_pipe_fds = True # Wait for exec to fail or succeed; possibly raising exception errpipe_read = FileObject(errpipe_read, 'rb') data = errpipe_read.read() finally: try: if hasattr(errpipe_read, 'close'): errpipe_read.close() else: os.close(errpipe_read) except OSError: # Especially on PyPy, we sometimes see the above # `os.close(errpipe_read)` raise an OSError. # It's not entirely clear why, but it happens in # InterprocessSignalTests.test_main sometimes, which must mean # we have some sort of race condition. pass finally: errpipe_read = -1 if data != b"": self.wait() child_exception = pickle.loads(data) for fd in (p2cwrite, c2pread, errread): if fd is not None and fd != -1: os.close(fd) if isinstance(child_exception, OSError): child_exception.filename = executable if hasattr(child_exception, '_failed_chdir'): child_exception.filename = cwd if getattr(child_exception, '_failed_chuser', False): child_exception.filename = None > raise child_exception E OSError: [Errno 8] Exec format error: 'locust' /usr/lib/python3/dist-packages/gevent/subprocess.py:1838: OSError _____________ StandaloneIntegrationTests.test_autostart_w_run_time _____________ self = @unittest.skipIf(sys.platform == "darwin", reason="This is too messy on macOS") def test_autostart_w_run_time(self): port = get_free_tcp_port() with mock_locustfile() as mocked: > proc = subprocess.Popen( [ "locust", "-f", mocked.file_path, "--web-port", str(port), "-t", "3", "--autostart", "--autoquit", "1", ], stdout=PIPE, stderr=PIPE, text=True, ) locust/test/test_main.py:635: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3/dist-packages/gevent/subprocess.py:808: in __init__ self._execute_child(args, executable, preexec_fn, close_fds, _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = args = ['locust', '-f', '/build/reproducible-path/locust-2.24.0/locust/test/mock_locustfile_1715255799_655901_77953.py', '--web-port', '35313', '-t', ...] executable = 'locust', preexec_fn = None, close_fds = True, pass_fds = () cwd = None, env = None, universal_newlines = None, startupinfo = None creationflags = 0, shell = False, p2cread = -1, p2cwrite = -1, c2pread = 11 c2pwrite = 80, errread = 81, errwrite = 82, restore_signals = True, gid = None gids = None, uid = None, umask = -1, start_new_session = False process_group = None def _execute_child(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, universal_newlines, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, restore_signals, gid, gids, uid, umask, start_new_session, process_group): """Execute program (POSIX version)""" if isinstance(args, (str, bytes)): args = [args] elif isinstance(args, PathLike): if shell: raise TypeError('path-like args is not allowed when ' 'shell is true') args = [fsencode(args)] # os.PathLike -> [str] else: args = list(args) if shell: # On Android the default shell is at '/system/bin/sh'. unix_shell = ( '/system/bin/sh' if hasattr(sys, 'getandroidapilevel') else '/bin/sh' ) args = [unix_shell, "-c"] + args if executable: args[0] = executable if executable is None: executable = args[0] self._loop.install_sigchld() # For transferring possible exec failure from child to parent # The first char specifies the exception type: 0 means # OSError, 1 means some other error. errpipe_read, errpipe_write = self.pipe_cloexec() # errpipe_write must not be in the standard io 0, 1, or 2 fd range. low_fds_to_close = [] while errpipe_write < 3: low_fds_to_close.append(errpipe_write) errpipe_write = os.dup(errpipe_write) for low_fd in low_fds_to_close: os.close(low_fd) try: try: gc_was_enabled = gc.isenabled() # Disable gc to avoid bug where gc -> file_dealloc -> # write to stderr -> hang. http://bugs.python.org/issue1336 gc.disable() try: self.pid = fork_and_watch(self._on_child, self._loop, True, fork) except: if gc_was_enabled: gc.enable() raise if self.pid == 0: # Child # In various places on the child side of things, we catch OSError # and add attributes to it that detail where in the process we failed; # like all exceptions until we have exec'd, this exception is pickled # and sent to the parent to raise in the calling process. # The parent uses this to decide how to treat that exception, # adjusting certain information about it as needed. # # Python 3.11.8 --- yes, a minor patch release --- stopped # letting the 'filename' parameter get set in the resulting # exception for many cases. We're not quite interpreting this # the same way the stdlib is, I'm sure, but this makes the stdlib # tests pass. # XXX: Technically we're doing a lot of stuff here that # may not be safe to do before a exec(), depending on the OS. # CPython 3 goes to great lengths to precompute a lot # of this info before the fork and pass it all to C functions that # try hard not to call things like malloc(). (Of course, # CPython 2 pretty much did what we're doing.) try: # Close parent's pipe ends if p2cwrite != -1: os.close(p2cwrite) if c2pread != -1: os.close(c2pread) if errread != -1: os.close(errread) os.close(errpipe_read) # When duping fds, if there arises a situation # where one of the fds is either 0, 1 or 2, it # is possible that it is overwritten (#12607). if c2pwrite == 0: c2pwrite = os.dup(c2pwrite) _set_inheritable(c2pwrite, False) while errwrite in (0, 1): errwrite = os.dup(errwrite) _set_inheritable(errwrite, False) # Dup fds for child def _dup2(existing, desired): # dup2() removes the CLOEXEC flag but # we must do it ourselves if dup2() # would be a no-op (issue #10806). if existing == desired: self._set_cloexec_flag(existing, False) elif existing != -1: os.dup2(existing, desired) try: self._remove_nonblock_flag(desired) except OSError: # Ignore EBADF, it may not actually be # open yet. # Tested beginning in 3.7.0b3 test_subprocess.py pass _dup2(p2cread, 0) _dup2(c2pwrite, 1) _dup2(errwrite, 2) # Close pipe fds. Make sure we don't close the # same fd more than once, or standard fds. if not True: closed = set([None]) for fd in (p2cread, c2pwrite, errwrite): if fd not in closed and fd > 2: os.close(fd) closed.add(fd) # Python 3 (with a working set_inheritable): # We no longer manually close p2cread, # c2pwrite, and errwrite here as # _close_open_fds takes care when it is # not already non-inheritable. if cwd is not None: try: os.chdir(cwd) except OSError as e: e._failed_chdir = True raise # Python 3.9 if umask >= 0: os.umask(umask) # XXX: CPython does _Py_RestoreSignals here. # Then setsid() based on ??? try: if gids: os.setgroups(gids) if gid: os.setregid(gid, gid) if uid: os.setreuid(uid, uid) if process_group is not None: os.setpgid(0, process_group) except OSError as e: e._failed_chuser = True raise if preexec_fn: preexec_fn() # Close all other fds, if asked for. This must be done # after preexec_fn runs. if close_fds: fds_to_keep = set(pass_fds) fds_to_keep.add(errpipe_write) self._close_fds(fds_to_keep, errpipe_write) if restore_signals: # restore the documented signals back to sig_dfl; # not all will be defined on every platform for sig in 'SIGPIPE', 'SIGXFZ', 'SIGXFSZ': sig = getattr(signal, sig, None) if sig is not None: signal.signal(sig, signal.SIG_DFL) if start_new_session: os.setsid() try: if env is None: os.execvp(executable, args) else: # Python 3.6 started testing for # bytes values in the env; it also # started encoding strs using # fsencode and using a lower-level # API that takes a list of keys # and values. We don't have access # to that API, so we go the reverse direction. env = {os.fsdecode(k) if isinstance(k, bytes) else k: os.fsdecode(v) if isinstance(v, bytes) else v for k, v in env.items()} os.execvpe(executable, args, env) except OSError as e: e._failed_exec = True raise except: exc_type, exc_value, tb = sys.exc_info() # Save the traceback and attach it to the exception object exc_lines = traceback.format_exception(exc_type, exc_value, tb) exc_value.child_traceback = ''.join(exc_lines) os.write(errpipe_write, pickle.dumps(exc_value)) finally: # Make sure that the process exits no matter what. # The return code does not matter much as it won't be # reported to the application os._exit(1) # Parent self._child_created = True if gc_was_enabled: gc.enable() finally: # be sure the FD is closed no matter what os.close(errpipe_write) # self._devnull is not always defined. devnull_fd = getattr(self, '_devnull', None) if p2cread != -1 and p2cwrite != -1 and p2cread != devnull_fd: os.close(p2cread) if c2pwrite != -1 and c2pread != -1 and c2pwrite != devnull_fd: os.close(c2pwrite) if errwrite != -1 and errread != -1 and errwrite != devnull_fd: os.close(errwrite) if devnull_fd is not None: os.close(devnull_fd) # Prevent a double close of these fds from __init__ on error. self._closed_child_pipe_fds = True # Wait for exec to fail or succeed; possibly raising exception errpipe_read = FileObject(errpipe_read, 'rb') data = errpipe_read.read() finally: try: if hasattr(errpipe_read, 'close'): errpipe_read.close() else: os.close(errpipe_read) except OSError: # Especially on PyPy, we sometimes see the above # `os.close(errpipe_read)` raise an OSError. # It's not entirely clear why, but it happens in # InterprocessSignalTests.test_main sometimes, which must mean # we have some sort of race condition. pass finally: errpipe_read = -1 if data != b"": self.wait() child_exception = pickle.loads(data) for fd in (p2cwrite, c2pread, errread): if fd is not None and fd != -1: os.close(fd) if isinstance(child_exception, OSError): child_exception.filename = executable if hasattr(child_exception, '_failed_chdir'): child_exception.filename = cwd if getattr(child_exception, '_failed_chuser', False): child_exception.filename = None > raise child_exception E OSError: [Errno 8] Exec format error: 'locust' /usr/lib/python3/dist-packages/gevent/subprocess.py:1838: OSError ____________ StandaloneIntegrationTests.test_autostart_wo_run_time _____________ self = @unittest.skipIf(os.name == "nt", reason="Signal handling on windows is hard") def test_autostart_wo_run_time(self): port = get_free_tcp_port() with mock_locustfile() as mocked: > proc = subprocess.Popen( [ "locust", "-f", mocked.file_path, "--web-port", str(port), "--autostart", ], stdout=PIPE, stderr=PIPE, text=True, ) locust/test/test_main.py:600: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3/dist-packages/gevent/subprocess.py:808: in __init__ self._execute_child(args, executable, preexec_fn, close_fds, _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = args = ['locust', '-f', '/build/reproducible-path/locust-2.24.0/locust/test/mock_locustfile_1715255799_8507774_31587.py', '--web-port', '36299', '--autostart'] executable = 'locust', preexec_fn = None, close_fds = True, pass_fds = () cwd = None, env = None, universal_newlines = None, startupinfo = None creationflags = 0, shell = False, p2cread = -1, p2cwrite = -1, c2pread = 11 c2pwrite = 80, errread = 81, errwrite = 82, restore_signals = True, gid = None gids = None, uid = None, umask = -1, start_new_session = False process_group = None def _execute_child(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, universal_newlines, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, restore_signals, gid, gids, uid, umask, start_new_session, process_group): """Execute program (POSIX version)""" if isinstance(args, (str, bytes)): args = [args] elif isinstance(args, PathLike): if shell: raise TypeError('path-like args is not allowed when ' 'shell is true') args = [fsencode(args)] # os.PathLike -> [str] else: args = list(args) if shell: # On Android the default shell is at '/system/bin/sh'. unix_shell = ( '/system/bin/sh' if hasattr(sys, 'getandroidapilevel') else '/bin/sh' ) args = [unix_shell, "-c"] + args if executable: args[0] = executable if executable is None: executable = args[0] self._loop.install_sigchld() # For transferring possible exec failure from child to parent # The first char specifies the exception type: 0 means # OSError, 1 means some other error. errpipe_read, errpipe_write = self.pipe_cloexec() # errpipe_write must not be in the standard io 0, 1, or 2 fd range. low_fds_to_close = [] while errpipe_write < 3: low_fds_to_close.append(errpipe_write) errpipe_write = os.dup(errpipe_write) for low_fd in low_fds_to_close: os.close(low_fd) try: try: gc_was_enabled = gc.isenabled() # Disable gc to avoid bug where gc -> file_dealloc -> # write to stderr -> hang. http://bugs.python.org/issue1336 gc.disable() try: self.pid = fork_and_watch(self._on_child, self._loop, True, fork) except: if gc_was_enabled: gc.enable() raise if self.pid == 0: # Child # In various places on the child side of things, we catch OSError # and add attributes to it that detail where in the process we failed; # like all exceptions until we have exec'd, this exception is pickled # and sent to the parent to raise in the calling process. # The parent uses this to decide how to treat that exception, # adjusting certain information about it as needed. # # Python 3.11.8 --- yes, a minor patch release --- stopped # letting the 'filename' parameter get set in the resulting # exception for many cases. We're not quite interpreting this # the same way the stdlib is, I'm sure, but this makes the stdlib # tests pass. # XXX: Technically we're doing a lot of stuff here that # may not be safe to do before a exec(), depending on the OS. # CPython 3 goes to great lengths to precompute a lot # of this info before the fork and pass it all to C functions that # try hard not to call things like malloc(). (Of course, # CPython 2 pretty much did what we're doing.) try: # Close parent's pipe ends if p2cwrite != -1: os.close(p2cwrite) if c2pread != -1: os.close(c2pread) if errread != -1: os.close(errread) os.close(errpipe_read) # When duping fds, if there arises a situation # where one of the fds is either 0, 1 or 2, it # is possible that it is overwritten (#12607). if c2pwrite == 0: c2pwrite = os.dup(c2pwrite) _set_inheritable(c2pwrite, False) while errwrite in (0, 1): errwrite = os.dup(errwrite) _set_inheritable(errwrite, False) # Dup fds for child def _dup2(existing, desired): # dup2() removes the CLOEXEC flag but # we must do it ourselves if dup2() # would be a no-op (issue #10806). if existing == desired: self._set_cloexec_flag(existing, False) elif existing != -1: os.dup2(existing, desired) try: self._remove_nonblock_flag(desired) except OSError: # Ignore EBADF, it may not actually be # open yet. # Tested beginning in 3.7.0b3 test_subprocess.py pass _dup2(p2cread, 0) _dup2(c2pwrite, 1) _dup2(errwrite, 2) # Close pipe fds. Make sure we don't close the # same fd more than once, or standard fds. if not True: closed = set([None]) for fd in (p2cread, c2pwrite, errwrite): if fd not in closed and fd > 2: os.close(fd) closed.add(fd) # Python 3 (with a working set_inheritable): # We no longer manually close p2cread, # c2pwrite, and errwrite here as # _close_open_fds takes care when it is # not already non-inheritable. if cwd is not None: try: os.chdir(cwd) except OSError as e: e._failed_chdir = True raise # Python 3.9 if umask >= 0: os.umask(umask) # XXX: CPython does _Py_RestoreSignals here. # Then setsid() based on ??? try: if gids: os.setgroups(gids) if gid: os.setregid(gid, gid) if uid: os.setreuid(uid, uid) if process_group is not None: os.setpgid(0, process_group) except OSError as e: e._failed_chuser = True raise if preexec_fn: preexec_fn() # Close all other fds, if asked for. This must be done # after preexec_fn runs. if close_fds: fds_to_keep = set(pass_fds) fds_to_keep.add(errpipe_write) self._close_fds(fds_to_keep, errpipe_write) if restore_signals: # restore the documented signals back to sig_dfl; # not all will be defined on every platform for sig in 'SIGPIPE', 'SIGXFZ', 'SIGXFSZ': sig = getattr(signal, sig, None) if sig is not None: signal.signal(sig, signal.SIG_DFL) if start_new_session: os.setsid() try: if env is None: os.execvp(executable, args) else: # Python 3.6 started testing for # bytes values in the env; it also # started encoding strs using # fsencode and using a lower-level # API that takes a list of keys # and values. We don't have access # to that API, so we go the reverse direction. env = {os.fsdecode(k) if isinstance(k, bytes) else k: os.fsdecode(v) if isinstance(v, bytes) else v for k, v in env.items()} os.execvpe(executable, args, env) except OSError as e: e._failed_exec = True raise except: exc_type, exc_value, tb = sys.exc_info() # Save the traceback and attach it to the exception object exc_lines = traceback.format_exception(exc_type, exc_value, tb) exc_value.child_traceback = ''.join(exc_lines) os.write(errpipe_write, pickle.dumps(exc_value)) finally: # Make sure that the process exits no matter what. # The return code does not matter much as it won't be # reported to the application os._exit(1) # Parent self._child_created = True if gc_was_enabled: gc.enable() finally: # be sure the FD is closed no matter what os.close(errpipe_write) # self._devnull is not always defined. devnull_fd = getattr(self, '_devnull', None) if p2cread != -1 and p2cwrite != -1 and p2cread != devnull_fd: os.close(p2cread) if c2pwrite != -1 and c2pread != -1 and c2pwrite != devnull_fd: os.close(c2pwrite) if errwrite != -1 and errread != -1 and errwrite != devnull_fd: os.close(errwrite) if devnull_fd is not None: os.close(devnull_fd) # Prevent a double close of these fds from __init__ on error. self._closed_child_pipe_fds = True # Wait for exec to fail or succeed; possibly raising exception errpipe_read = FileObject(errpipe_read, 'rb') data = errpipe_read.read() finally: try: if hasattr(errpipe_read, 'close'): errpipe_read.close() else: os.close(errpipe_read) except OSError: # Especially on PyPy, we sometimes see the above # `os.close(errpipe_read)` raise an OSError. # It's not entirely clear why, but it happens in # InterprocessSignalTests.test_main sometimes, which must mean # we have some sort of race condition. pass finally: errpipe_read = -1 if data != b"": self.wait() child_exception = pickle.loads(data) for fd in (p2cwrite, c2pread, errread): if fd is not None and fd != -1: os.close(fd) if isinstance(child_exception, OSError): child_exception.filename = executable if hasattr(child_exception, '_failed_chdir'): child_exception.filename = cwd if getattr(child_exception, '_failed_chuser', False): child_exception.filename = None > raise child_exception E OSError: [Errno 8] Exec format error: 'locust' /usr/lib/python3/dist-packages/gevent/subprocess.py:1838: OSError _________ StandaloneIntegrationTests.test_command_line_user_selection __________ self = def test_command_line_user_selection(self): LOCUSTFILE_CONTENT = textwrap.dedent( """ from locust import User, task, constant class User1(User): wait_time = constant(1) @task def t(self): print("User1 is running") class User2(User): wait_time = constant(1) @task def t(self): print("User2 is running") class User3(User): wait_time = constant(1) @task def t(self): print("User3 is running") """ ) with mock_locustfile(content=LOCUSTFILE_CONTENT) as mocked: proc = subprocess.Popen( " ".join( [ "locust", "-f", mocked.file_path, "--headless", "--run-time", "2s", "-u", "5", "-r", "10", "User2", "User3", ] ), stderr=STDOUT, stdout=PIPE, shell=True, text=True, ) output = proc.communicate()[0] self.assertNotIn("User1 is running", output) > self.assertIn("User2 is running", output) E AssertionError: 'User2 is running' not found in '/build/reproducible-path/locust-2.24.0/debian/locust: line 2: from: command not found\n/build/reproducible-path/locust-2.24.0/debian/locust: line 5: syntax error: unexpected end of file\n' locust/test/test_main.py:1080: AssertionError _______________ StandaloneIntegrationTests.test_custom_arguments _______________ self = @unittest.skipIf(os.name == "nt", reason="Signal handling on windows is hard") def test_custom_arguments(self): port = get_free_tcp_port() with temporary_file( content=textwrap.dedent( """ from locust import User, task, constant, events @events.init_command_line_parser.add_listener def _(parser, **kw): parser.add_argument("--custom-string-arg") class TestUser(User): wait_time = constant(10) @task def my_task(self): print(self.environment.parsed_options.custom_string_arg) """ ) ) as file_path: # print(subprocess.check_output(["cat", file_path])) > proc = subprocess.Popen( ["locust", "-f", file_path, "--custom-string-arg", "command_line_value", "--web-port", str(port)], stdout=PIPE, stderr=PIPE, text=True, ) locust/test/test_main.py:104: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3/dist-packages/gevent/subprocess.py:808: in __init__ self._execute_child(args, executable, preexec_fn, close_fds, _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = args = ['locust', '-f', '/tmp/tmpozjl89cx_locustfile.py', '--custom-string-arg', 'command_line_value', '--web-port', ...] executable = 'locust', preexec_fn = None, close_fds = True, pass_fds = () cwd = None, env = None, universal_newlines = None, startupinfo = None creationflags = 0, shell = False, p2cread = -1, p2cwrite = -1, c2pread = 11 c2pwrite = 80, errread = 81, errwrite = 82, restore_signals = True, gid = None gids = None, uid = None, umask = -1, start_new_session = False process_group = None def _execute_child(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, universal_newlines, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, restore_signals, gid, gids, uid, umask, start_new_session, process_group): """Execute program (POSIX version)""" if isinstance(args, (str, bytes)): args = [args] elif isinstance(args, PathLike): if shell: raise TypeError('path-like args is not allowed when ' 'shell is true') args = [fsencode(args)] # os.PathLike -> [str] else: args = list(args) if shell: # On Android the default shell is at '/system/bin/sh'. unix_shell = ( '/system/bin/sh' if hasattr(sys, 'getandroidapilevel') else '/bin/sh' ) args = [unix_shell, "-c"] + args if executable: args[0] = executable if executable is None: executable = args[0] self._loop.install_sigchld() # For transferring possible exec failure from child to parent # The first char specifies the exception type: 0 means # OSError, 1 means some other error. errpipe_read, errpipe_write = self.pipe_cloexec() # errpipe_write must not be in the standard io 0, 1, or 2 fd range. low_fds_to_close = [] while errpipe_write < 3: low_fds_to_close.append(errpipe_write) errpipe_write = os.dup(errpipe_write) for low_fd in low_fds_to_close: os.close(low_fd) try: try: gc_was_enabled = gc.isenabled() # Disable gc to avoid bug where gc -> file_dealloc -> # write to stderr -> hang. http://bugs.python.org/issue1336 gc.disable() try: self.pid = fork_and_watch(self._on_child, self._loop, True, fork) except: if gc_was_enabled: gc.enable() raise if self.pid == 0: # Child # In various places on the child side of things, we catch OSError # and add attributes to it that detail where in the process we failed; # like all exceptions until we have exec'd, this exception is pickled # and sent to the parent to raise in the calling process. # The parent uses this to decide how to treat that exception, # adjusting certain information about it as needed. # # Python 3.11.8 --- yes, a minor patch release --- stopped # letting the 'filename' parameter get set in the resulting # exception for many cases. We're not quite interpreting this # the same way the stdlib is, I'm sure, but this makes the stdlib # tests pass. # XXX: Technically we're doing a lot of stuff here that # may not be safe to do before a exec(), depending on the OS. # CPython 3 goes to great lengths to precompute a lot # of this info before the fork and pass it all to C functions that # try hard not to call things like malloc(). (Of course, # CPython 2 pretty much did what we're doing.) try: # Close parent's pipe ends if p2cwrite != -1: os.close(p2cwrite) if c2pread != -1: os.close(c2pread) if errread != -1: os.close(errread) os.close(errpipe_read) # When duping fds, if there arises a situation # where one of the fds is either 0, 1 or 2, it # is possible that it is overwritten (#12607). if c2pwrite == 0: c2pwrite = os.dup(c2pwrite) _set_inheritable(c2pwrite, False) while errwrite in (0, 1): errwrite = os.dup(errwrite) _set_inheritable(errwrite, False) # Dup fds for child def _dup2(existing, desired): # dup2() removes the CLOEXEC flag but # we must do it ourselves if dup2() # would be a no-op (issue #10806). if existing == desired: self._set_cloexec_flag(existing, False) elif existing != -1: os.dup2(existing, desired) try: self._remove_nonblock_flag(desired) except OSError: # Ignore EBADF, it may not actually be # open yet. # Tested beginning in 3.7.0b3 test_subprocess.py pass _dup2(p2cread, 0) _dup2(c2pwrite, 1) _dup2(errwrite, 2) # Close pipe fds. Make sure we don't close the # same fd more than once, or standard fds. if not True: closed = set([None]) for fd in (p2cread, c2pwrite, errwrite): if fd not in closed and fd > 2: os.close(fd) closed.add(fd) # Python 3 (with a working set_inheritable): # We no longer manually close p2cread, # c2pwrite, and errwrite here as # _close_open_fds takes care when it is # not already non-inheritable. if cwd is not None: try: os.chdir(cwd) except OSError as e: e._failed_chdir = True raise # Python 3.9 if umask >= 0: os.umask(umask) # XXX: CPython does _Py_RestoreSignals here. # Then setsid() based on ??? try: if gids: os.setgroups(gids) if gid: os.setregid(gid, gid) if uid: os.setreuid(uid, uid) if process_group is not None: os.setpgid(0, process_group) except OSError as e: e._failed_chuser = True raise if preexec_fn: preexec_fn() # Close all other fds, if asked for. This must be done # after preexec_fn runs. if close_fds: fds_to_keep = set(pass_fds) fds_to_keep.add(errpipe_write) self._close_fds(fds_to_keep, errpipe_write) if restore_signals: # restore the documented signals back to sig_dfl; # not all will be defined on every platform for sig in 'SIGPIPE', 'SIGXFZ', 'SIGXFSZ': sig = getattr(signal, sig, None) if sig is not None: signal.signal(sig, signal.SIG_DFL) if start_new_session: os.setsid() try: if env is None: os.execvp(executable, args) else: # Python 3.6 started testing for # bytes values in the env; it also # started encoding strs using # fsencode and using a lower-level # API that takes a list of keys # and values. We don't have access # to that API, so we go the reverse direction. env = {os.fsdecode(k) if isinstance(k, bytes) else k: os.fsdecode(v) if isinstance(v, bytes) else v for k, v in env.items()} os.execvpe(executable, args, env) except OSError as e: e._failed_exec = True raise except: exc_type, exc_value, tb = sys.exc_info() # Save the traceback and attach it to the exception object exc_lines = traceback.format_exception(exc_type, exc_value, tb) exc_value.child_traceback = ''.join(exc_lines) os.write(errpipe_write, pickle.dumps(exc_value)) finally: # Make sure that the process exits no matter what. # The return code does not matter much as it won't be # reported to the application os._exit(1) # Parent self._child_created = True if gc_was_enabled: gc.enable() finally: # be sure the FD is closed no matter what os.close(errpipe_write) # self._devnull is not always defined. devnull_fd = getattr(self, '_devnull', None) if p2cread != -1 and p2cwrite != -1 and p2cread != devnull_fd: os.close(p2cread) if c2pwrite != -1 and c2pread != -1 and c2pwrite != devnull_fd: os.close(c2pwrite) if errwrite != -1 and errread != -1 and errwrite != devnull_fd: os.close(errwrite) if devnull_fd is not None: os.close(devnull_fd) # Prevent a double close of these fds from __init__ on error. self._closed_child_pipe_fds = True # Wait for exec to fail or succeed; possibly raising exception errpipe_read = FileObject(errpipe_read, 'rb') data = errpipe_read.read() finally: try: if hasattr(errpipe_read, 'close'): errpipe_read.close() else: os.close(errpipe_read) except OSError: # Especially on PyPy, we sometimes see the above # `os.close(errpipe_read)` raise an OSError. # It's not entirely clear why, but it happens in # InterprocessSignalTests.test_main sometimes, which must mean # we have some sort of race condition. pass finally: errpipe_read = -1 if data != b"": self.wait() child_exception = pickle.loads(data) for fd in (p2cwrite, c2pread, errread): if fd is not None and fd != -1: os.close(fd) if isinstance(child_exception, OSError): child_exception.filename = executable if hasattr(child_exception, '_failed_chdir'): child_exception.filename = cwd if getattr(child_exception, '_failed_chuser', False): child_exception.filename = None > raise child_exception E OSError: [Errno 8] Exec format error: 'locust' /usr/lib/python3/dist-packages/gevent/subprocess.py:1838: OSError ___________ StandaloneIntegrationTests.test_custom_arguments_in_file ___________ self = @unittest.skipIf(os.name == "nt", reason="Signal handling on windows is hard") def test_custom_arguments_in_file(self): with temporary_file( content=textwrap.dedent( """ from locust import User, task, constant, events @events.init_command_line_parser.add_listener def _(parser, **kw): parser.add_argument("--custom-string-arg") class TestUser(User): wait_time = constant(10) @task def my_task(self): print(self.environment.parsed_options.custom_string_arg) """ ) ) as file_path: try: with open("locust.conf", "w") as conf_file: conf_file.write("custom-string-arg config_file_value") > proc = subprocess.Popen( ["locust", "-f", file_path, "--autostart"], stdout=PIPE, stderr=PIPE, text=True, ) locust/test/test_main.py:147: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3/dist-packages/gevent/subprocess.py:808: in __init__ self._execute_child(args, executable, preexec_fn, close_fds, _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = args = ['locust', '-f', '/tmp/tmpresr8855_locustfile.py', '--autostart'] executable = 'locust', preexec_fn = None, close_fds = True, pass_fds = () cwd = None, env = None, universal_newlines = None, startupinfo = None creationflags = 0, shell = False, p2cread = -1, p2cwrite = -1, c2pread = 11 c2pwrite = 80, errread = 81, errwrite = 82, restore_signals = True, gid = None gids = None, uid = None, umask = -1, start_new_session = False process_group = None def _execute_child(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, universal_newlines, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, restore_signals, gid, gids, uid, umask, start_new_session, process_group): """Execute program (POSIX version)""" if isinstance(args, (str, bytes)): args = [args] elif isinstance(args, PathLike): if shell: raise TypeError('path-like args is not allowed when ' 'shell is true') args = [fsencode(args)] # os.PathLike -> [str] else: args = list(args) if shell: # On Android the default shell is at '/system/bin/sh'. unix_shell = ( '/system/bin/sh' if hasattr(sys, 'getandroidapilevel') else '/bin/sh' ) args = [unix_shell, "-c"] + args if executable: args[0] = executable if executable is None: executable = args[0] self._loop.install_sigchld() # For transferring possible exec failure from child to parent # The first char specifies the exception type: 0 means # OSError, 1 means some other error. errpipe_read, errpipe_write = self.pipe_cloexec() # errpipe_write must not be in the standard io 0, 1, or 2 fd range. low_fds_to_close = [] while errpipe_write < 3: low_fds_to_close.append(errpipe_write) errpipe_write = os.dup(errpipe_write) for low_fd in low_fds_to_close: os.close(low_fd) try: try: gc_was_enabled = gc.isenabled() # Disable gc to avoid bug where gc -> file_dealloc -> # write to stderr -> hang. http://bugs.python.org/issue1336 gc.disable() try: self.pid = fork_and_watch(self._on_child, self._loop, True, fork) except: if gc_was_enabled: gc.enable() raise if self.pid == 0: # Child # In various places on the child side of things, we catch OSError # and add attributes to it that detail where in the process we failed; # like all exceptions until we have exec'd, this exception is pickled # and sent to the parent to raise in the calling process. # The parent uses this to decide how to treat that exception, # adjusting certain information about it as needed. # # Python 3.11.8 --- yes, a minor patch release --- stopped # letting the 'filename' parameter get set in the resulting # exception for many cases. We're not quite interpreting this # the same way the stdlib is, I'm sure, but this makes the stdlib # tests pass. # XXX: Technically we're doing a lot of stuff here that # may not be safe to do before a exec(), depending on the OS. # CPython 3 goes to great lengths to precompute a lot # of this info before the fork and pass it all to C functions that # try hard not to call things like malloc(). (Of course, # CPython 2 pretty much did what we're doing.) try: # Close parent's pipe ends if p2cwrite != -1: os.close(p2cwrite) if c2pread != -1: os.close(c2pread) if errread != -1: os.close(errread) os.close(errpipe_read) # When duping fds, if there arises a situation # where one of the fds is either 0, 1 or 2, it # is possible that it is overwritten (#12607). if c2pwrite == 0: c2pwrite = os.dup(c2pwrite) _set_inheritable(c2pwrite, False) while errwrite in (0, 1): errwrite = os.dup(errwrite) _set_inheritable(errwrite, False) # Dup fds for child def _dup2(existing, desired): # dup2() removes the CLOEXEC flag but # we must do it ourselves if dup2() # would be a no-op (issue #10806). if existing == desired: self._set_cloexec_flag(existing, False) elif existing != -1: os.dup2(existing, desired) try: self._remove_nonblock_flag(desired) except OSError: # Ignore EBADF, it may not actually be # open yet. # Tested beginning in 3.7.0b3 test_subprocess.py pass _dup2(p2cread, 0) _dup2(c2pwrite, 1) _dup2(errwrite, 2) # Close pipe fds. Make sure we don't close the # same fd more than once, or standard fds. if not True: closed = set([None]) for fd in (p2cread, c2pwrite, errwrite): if fd not in closed and fd > 2: os.close(fd) closed.add(fd) # Python 3 (with a working set_inheritable): # We no longer manually close p2cread, # c2pwrite, and errwrite here as # _close_open_fds takes care when it is # not already non-inheritable. if cwd is not None: try: os.chdir(cwd) except OSError as e: e._failed_chdir = True raise # Python 3.9 if umask >= 0: os.umask(umask) # XXX: CPython does _Py_RestoreSignals here. # Then setsid() based on ??? try: if gids: os.setgroups(gids) if gid: os.setregid(gid, gid) if uid: os.setreuid(uid, uid) if process_group is not None: os.setpgid(0, process_group) except OSError as e: e._failed_chuser = True raise if preexec_fn: preexec_fn() # Close all other fds, if asked for. This must be done # after preexec_fn runs. if close_fds: fds_to_keep = set(pass_fds) fds_to_keep.add(errpipe_write) self._close_fds(fds_to_keep, errpipe_write) if restore_signals: # restore the documented signals back to sig_dfl; # not all will be defined on every platform for sig in 'SIGPIPE', 'SIGXFZ', 'SIGXFSZ': sig = getattr(signal, sig, None) if sig is not None: signal.signal(sig, signal.SIG_DFL) if start_new_session: os.setsid() try: if env is None: os.execvp(executable, args) else: # Python 3.6 started testing for # bytes values in the env; it also # started encoding strs using # fsencode and using a lower-level # API that takes a list of keys # and values. We don't have access # to that API, so we go the reverse direction. env = {os.fsdecode(k) if isinstance(k, bytes) else k: os.fsdecode(v) if isinstance(v, bytes) else v for k, v in env.items()} os.execvpe(executable, args, env) except OSError as e: e._failed_exec = True raise except: exc_type, exc_value, tb = sys.exc_info() # Save the traceback and attach it to the exception object exc_lines = traceback.format_exception(exc_type, exc_value, tb) exc_value.child_traceback = ''.join(exc_lines) os.write(errpipe_write, pickle.dumps(exc_value)) finally: # Make sure that the process exits no matter what. # The return code does not matter much as it won't be # reported to the application os._exit(1) # Parent self._child_created = True if gc_was_enabled: gc.enable() finally: # be sure the FD is closed no matter what os.close(errpipe_write) # self._devnull is not always defined. devnull_fd = getattr(self, '_devnull', None) if p2cread != -1 and p2cwrite != -1 and p2cread != devnull_fd: os.close(p2cread) if c2pwrite != -1 and c2pread != -1 and c2pwrite != devnull_fd: os.close(c2pwrite) if errwrite != -1 and errread != -1 and errwrite != devnull_fd: os.close(errwrite) if devnull_fd is not None: os.close(devnull_fd) # Prevent a double close of these fds from __init__ on error. self._closed_child_pipe_fds = True # Wait for exec to fail or succeed; possibly raising exception errpipe_read = FileObject(errpipe_read, 'rb') data = errpipe_read.read() finally: try: if hasattr(errpipe_read, 'close'): errpipe_read.close() else: os.close(errpipe_read) except OSError: # Especially on PyPy, we sometimes see the above # `os.close(errpipe_read)` raise an OSError. # It's not entirely clear why, but it happens in # InterprocessSignalTests.test_main sometimes, which must mean # we have some sort of race condition. pass finally: errpipe_read = -1 if data != b"": self.wait() child_exception = pickle.loads(data) for fd in (p2cwrite, c2pread, errread): if fd is not None and fd != -1: os.close(fd) if isinstance(child_exception, OSError): child_exception.filename = executable if hasattr(child_exception, '_failed_chdir'): child_exception.filename = cwd if getattr(child_exception, '_failed_chuser', False): child_exception.filename = None > raise child_exception E OSError: [Errno 8] Exec format error: 'locust' /usr/lib/python3/dist-packages/gevent/subprocess.py:1838: OSError _______________ StandaloneIntegrationTests.test_custom_exit_code _______________ self = @unittest.skipIf(os.name == "nt", reason="Signal handling on windows is hard") def test_custom_exit_code(self): with temporary_file( content=textwrap.dedent( """ from locust import User, task, constant, events @events.quitting.add_listener def _(environment, **kw): environment.process_exit_code = 42 @events.quit.add_listener def _(exit_code, **kw): print(f"Exit code in quit event {exit_code}") class TestUser(User): wait_time = constant(3) @task def my_task(self): print("running my_task()") """ ) ) as file_path: > proc = subprocess.Popen(["locust", "-f", file_path], stdout=PIPE, stderr=PIPE, text=True) locust/test/test_main.py:182: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3/dist-packages/gevent/subprocess.py:808: in __init__ self._execute_child(args, executable, preexec_fn, close_fds, _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = args = ['locust', '-f', '/tmp/tmpbjejc4ok_locustfile.py'], executable = 'locust' preexec_fn = None, close_fds = True, pass_fds = (), cwd = None, env = None universal_newlines = None, startupinfo = None, creationflags = 0, shell = False p2cread = -1, p2cwrite = -1, c2pread = 11, c2pwrite = 80, errread = 81 errwrite = 82, restore_signals = True, gid = None, gids = None, uid = None umask = -1, start_new_session = False, process_group = None def _execute_child(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, universal_newlines, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, restore_signals, gid, gids, uid, umask, start_new_session, process_group): """Execute program (POSIX version)""" if isinstance(args, (str, bytes)): args = [args] elif isinstance(args, PathLike): if shell: raise TypeError('path-like args is not allowed when ' 'shell is true') args = [fsencode(args)] # os.PathLike -> [str] else: args = list(args) if shell: # On Android the default shell is at '/system/bin/sh'. unix_shell = ( '/system/bin/sh' if hasattr(sys, 'getandroidapilevel') else '/bin/sh' ) args = [unix_shell, "-c"] + args if executable: args[0] = executable if executable is None: executable = args[0] self._loop.install_sigchld() # For transferring possible exec failure from child to parent # The first char specifies the exception type: 0 means # OSError, 1 means some other error. errpipe_read, errpipe_write = self.pipe_cloexec() # errpipe_write must not be in the standard io 0, 1, or 2 fd range. low_fds_to_close = [] while errpipe_write < 3: low_fds_to_close.append(errpipe_write) errpipe_write = os.dup(errpipe_write) for low_fd in low_fds_to_close: os.close(low_fd) try: try: gc_was_enabled = gc.isenabled() # Disable gc to avoid bug where gc -> file_dealloc -> # write to stderr -> hang. http://bugs.python.org/issue1336 gc.disable() try: self.pid = fork_and_watch(self._on_child, self._loop, True, fork) except: if gc_was_enabled: gc.enable() raise if self.pid == 0: # Child # In various places on the child side of things, we catch OSError # and add attributes to it that detail where in the process we failed; # like all exceptions until we have exec'd, this exception is pickled # and sent to the parent to raise in the calling process. # The parent uses this to decide how to treat that exception, # adjusting certain information about it as needed. # # Python 3.11.8 --- yes, a minor patch release --- stopped # letting the 'filename' parameter get set in the resulting # exception for many cases. We're not quite interpreting this # the same way the stdlib is, I'm sure, but this makes the stdlib # tests pass. # XXX: Technically we're doing a lot of stuff here that # may not be safe to do before a exec(), depending on the OS. # CPython 3 goes to great lengths to precompute a lot # of this info before the fork and pass it all to C functions that # try hard not to call things like malloc(). (Of course, # CPython 2 pretty much did what we're doing.) try: # Close parent's pipe ends if p2cwrite != -1: os.close(p2cwrite) if c2pread != -1: os.close(c2pread) if errread != -1: os.close(errread) os.close(errpipe_read) # When duping fds, if there arises a situation # where one of the fds is either 0, 1 or 2, it # is possible that it is overwritten (#12607). if c2pwrite == 0: c2pwrite = os.dup(c2pwrite) _set_inheritable(c2pwrite, False) while errwrite in (0, 1): errwrite = os.dup(errwrite) _set_inheritable(errwrite, False) # Dup fds for child def _dup2(existing, desired): # dup2() removes the CLOEXEC flag but # we must do it ourselves if dup2() # would be a no-op (issue #10806). if existing == desired: self._set_cloexec_flag(existing, False) elif existing != -1: os.dup2(existing, desired) try: self._remove_nonblock_flag(desired) except OSError: # Ignore EBADF, it may not actually be # open yet. # Tested beginning in 3.7.0b3 test_subprocess.py pass _dup2(p2cread, 0) _dup2(c2pwrite, 1) _dup2(errwrite, 2) # Close pipe fds. Make sure we don't close the # same fd more than once, or standard fds. if not True: closed = set([None]) for fd in (p2cread, c2pwrite, errwrite): if fd not in closed and fd > 2: os.close(fd) closed.add(fd) # Python 3 (with a working set_inheritable): # We no longer manually close p2cread, # c2pwrite, and errwrite here as # _close_open_fds takes care when it is # not already non-inheritable. if cwd is not None: try: os.chdir(cwd) except OSError as e: e._failed_chdir = True raise # Python 3.9 if umask >= 0: os.umask(umask) # XXX: CPython does _Py_RestoreSignals here. # Then setsid() based on ??? try: if gids: os.setgroups(gids) if gid: os.setregid(gid, gid) if uid: os.setreuid(uid, uid) if process_group is not None: os.setpgid(0, process_group) except OSError as e: e._failed_chuser = True raise if preexec_fn: preexec_fn() # Close all other fds, if asked for. This must be done # after preexec_fn runs. if close_fds: fds_to_keep = set(pass_fds) fds_to_keep.add(errpipe_write) self._close_fds(fds_to_keep, errpipe_write) if restore_signals: # restore the documented signals back to sig_dfl; # not all will be defined on every platform for sig in 'SIGPIPE', 'SIGXFZ', 'SIGXFSZ': sig = getattr(signal, sig, None) if sig is not None: signal.signal(sig, signal.SIG_DFL) if start_new_session: os.setsid() try: if env is None: os.execvp(executable, args) else: # Python 3.6 started testing for # bytes values in the env; it also # started encoding strs using # fsencode and using a lower-level # API that takes a list of keys # and values. We don't have access # to that API, so we go the reverse direction. env = {os.fsdecode(k) if isinstance(k, bytes) else k: os.fsdecode(v) if isinstance(v, bytes) else v for k, v in env.items()} os.execvpe(executable, args, env) except OSError as e: e._failed_exec = True raise except: exc_type, exc_value, tb = sys.exc_info() # Save the traceback and attach it to the exception object exc_lines = traceback.format_exception(exc_type, exc_value, tb) exc_value.child_traceback = ''.join(exc_lines) os.write(errpipe_write, pickle.dumps(exc_value)) finally: # Make sure that the process exits no matter what. # The return code does not matter much as it won't be # reported to the application os._exit(1) # Parent self._child_created = True if gc_was_enabled: gc.enable() finally: # be sure the FD is closed no matter what os.close(errpipe_write) # self._devnull is not always defined. devnull_fd = getattr(self, '_devnull', None) if p2cread != -1 and p2cwrite != -1 and p2cread != devnull_fd: os.close(p2cread) if c2pwrite != -1 and c2pread != -1 and c2pwrite != devnull_fd: os.close(c2pwrite) if errwrite != -1 and errread != -1 and errwrite != devnull_fd: os.close(errwrite) if devnull_fd is not None: os.close(devnull_fd) # Prevent a double close of these fds from __init__ on error. self._closed_child_pipe_fds = True # Wait for exec to fail or succeed; possibly raising exception errpipe_read = FileObject(errpipe_read, 'rb') data = errpipe_read.read() finally: try: if hasattr(errpipe_read, 'close'): errpipe_read.close() else: os.close(errpipe_read) except OSError: # Especially on PyPy, we sometimes see the above # `os.close(errpipe_read)` raise an OSError. # It's not entirely clear why, but it happens in # InterprocessSignalTests.test_main sometimes, which must mean # we have some sort of race condition. pass finally: errpipe_read = -1 if data != b"": self.wait() child_exception = pickle.loads(data) for fd in (p2cwrite, c2pread, errread): if fd is not None and fd != -1: os.close(fd) if isinstance(child_exception, OSError): child_exception.filename = executable if hasattr(child_exception, '_failed_chdir'): child_exception.filename = cwd if getattr(child_exception, '_failed_chuser', False): child_exception.filename = None > raise child_exception E OSError: [Errno 8] Exec format error: 'locust' /usr/lib/python3/dist-packages/gevent/subprocess.py:1838: OSError ________ StandaloneIntegrationTests.test_default_headless_spawn_options ________ self = def test_default_headless_spawn_options(self): with mock_locustfile() as mocked: > proc = subprocess.Popen( [ "locust", "-f", mocked.file_path, "--host", "https://test.com/", "--run-time", "1s", "--headless", "--loglevel", "DEBUG", "--exit-code-on-error", "0", # just to test --stop-timeout argument parsing, doesnt actually validate its function: "--stop-timeout", "1s", ], stdout=PIPE, stderr=PIPE, text=True, ) locust/test/test_main.py:371: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3/dist-packages/gevent/subprocess.py:808: in __init__ self._execute_child(args, executable, preexec_fn, close_fds, _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = args = ['locust', '-f', '/build/reproducible-path/locust-2.24.0/locust/test/mock_locustfile_1715255800_696904_45886.py', '--host', 'https://test.com/', '--run-time', ...] executable = 'locust', preexec_fn = None, close_fds = True, pass_fds = () cwd = None, env = None, universal_newlines = None, startupinfo = None creationflags = 0, shell = False, p2cread = -1, p2cwrite = -1, c2pread = 11 c2pwrite = 80, errread = 81, errwrite = 82, restore_signals = True, gid = None gids = None, uid = None, umask = -1, start_new_session = False process_group = None def _execute_child(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, universal_newlines, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, restore_signals, gid, gids, uid, umask, start_new_session, process_group): """Execute program (POSIX version)""" if isinstance(args, (str, bytes)): args = [args] elif isinstance(args, PathLike): if shell: raise TypeError('path-like args is not allowed when ' 'shell is true') args = [fsencode(args)] # os.PathLike -> [str] else: args = list(args) if shell: # On Android the default shell is at '/system/bin/sh'. unix_shell = ( '/system/bin/sh' if hasattr(sys, 'getandroidapilevel') else '/bin/sh' ) args = [unix_shell, "-c"] + args if executable: args[0] = executable if executable is None: executable = args[0] self._loop.install_sigchld() # For transferring possible exec failure from child to parent # The first char specifies the exception type: 0 means # OSError, 1 means some other error. errpipe_read, errpipe_write = self.pipe_cloexec() # errpipe_write must not be in the standard io 0, 1, or 2 fd range. low_fds_to_close = [] while errpipe_write < 3: low_fds_to_close.append(errpipe_write) errpipe_write = os.dup(errpipe_write) for low_fd in low_fds_to_close: os.close(low_fd) try: try: gc_was_enabled = gc.isenabled() # Disable gc to avoid bug where gc -> file_dealloc -> # write to stderr -> hang. http://bugs.python.org/issue1336 gc.disable() try: self.pid = fork_and_watch(self._on_child, self._loop, True, fork) except: if gc_was_enabled: gc.enable() raise if self.pid == 0: # Child # In various places on the child side of things, we catch OSError # and add attributes to it that detail where in the process we failed; # like all exceptions until we have exec'd, this exception is pickled # and sent to the parent to raise in the calling process. # The parent uses this to decide how to treat that exception, # adjusting certain information about it as needed. # # Python 3.11.8 --- yes, a minor patch release --- stopped # letting the 'filename' parameter get set in the resulting # exception for many cases. We're not quite interpreting this # the same way the stdlib is, I'm sure, but this makes the stdlib # tests pass. # XXX: Technically we're doing a lot of stuff here that # may not be safe to do before a exec(), depending on the OS. # CPython 3 goes to great lengths to precompute a lot # of this info before the fork and pass it all to C functions that # try hard not to call things like malloc(). (Of course, # CPython 2 pretty much did what we're doing.) try: # Close parent's pipe ends if p2cwrite != -1: os.close(p2cwrite) if c2pread != -1: os.close(c2pread) if errread != -1: os.close(errread) os.close(errpipe_read) # When duping fds, if there arises a situation # where one of the fds is either 0, 1 or 2, it # is possible that it is overwritten (#12607). if c2pwrite == 0: c2pwrite = os.dup(c2pwrite) _set_inheritable(c2pwrite, False) while errwrite in (0, 1): errwrite = os.dup(errwrite) _set_inheritable(errwrite, False) # Dup fds for child def _dup2(existing, desired): # dup2() removes the CLOEXEC flag but # we must do it ourselves if dup2() # would be a no-op (issue #10806). if existing == desired: self._set_cloexec_flag(existing, False) elif existing != -1: os.dup2(existing, desired) try: self._remove_nonblock_flag(desired) except OSError: # Ignore EBADF, it may not actually be # open yet. # Tested beginning in 3.7.0b3 test_subprocess.py pass _dup2(p2cread, 0) _dup2(c2pwrite, 1) _dup2(errwrite, 2) # Close pipe fds. Make sure we don't close the # same fd more than once, or standard fds. if not True: closed = set([None]) for fd in (p2cread, c2pwrite, errwrite): if fd not in closed and fd > 2: os.close(fd) closed.add(fd) # Python 3 (with a working set_inheritable): # We no longer manually close p2cread, # c2pwrite, and errwrite here as # _close_open_fds takes care when it is # not already non-inheritable. if cwd is not None: try: os.chdir(cwd) except OSError as e: e._failed_chdir = True raise # Python 3.9 if umask >= 0: os.umask(umask) # XXX: CPython does _Py_RestoreSignals here. # Then setsid() based on ??? try: if gids: os.setgroups(gids) if gid: os.setregid(gid, gid) if uid: os.setreuid(uid, uid) if process_group is not None: os.setpgid(0, process_group) except OSError as e: e._failed_chuser = True raise if preexec_fn: preexec_fn() # Close all other fds, if asked for. This must be done # after preexec_fn runs. if close_fds: fds_to_keep = set(pass_fds) fds_to_keep.add(errpipe_write) self._close_fds(fds_to_keep, errpipe_write) if restore_signals: # restore the documented signals back to sig_dfl; # not all will be defined on every platform for sig in 'SIGPIPE', 'SIGXFZ', 'SIGXFSZ': sig = getattr(signal, sig, None) if sig is not None: signal.signal(sig, signal.SIG_DFL) if start_new_session: os.setsid() try: if env is None: os.execvp(executable, args) else: # Python 3.6 started testing for # bytes values in the env; it also # started encoding strs using # fsencode and using a lower-level # API that takes a list of keys # and values. We don't have access # to that API, so we go the reverse direction. env = {os.fsdecode(k) if isinstance(k, bytes) else k: os.fsdecode(v) if isinstance(v, bytes) else v for k, v in env.items()} os.execvpe(executable, args, env) except OSError as e: e._failed_exec = True raise except: exc_type, exc_value, tb = sys.exc_info() # Save the traceback and attach it to the exception object exc_lines = traceback.format_exception(exc_type, exc_value, tb) exc_value.child_traceback = ''.join(exc_lines) os.write(errpipe_write, pickle.dumps(exc_value)) finally: # Make sure that the process exits no matter what. # The return code does not matter much as it won't be # reported to the application os._exit(1) # Parent self._child_created = True if gc_was_enabled: gc.enable() finally: # be sure the FD is closed no matter what os.close(errpipe_write) # self._devnull is not always defined. devnull_fd = getattr(self, '_devnull', None) if p2cread != -1 and p2cwrite != -1 and p2cread != devnull_fd: os.close(p2cread) if c2pwrite != -1 and c2pread != -1 and c2pwrite != devnull_fd: os.close(c2pwrite) if errwrite != -1 and errread != -1 and errwrite != devnull_fd: os.close(errwrite) if devnull_fd is not None: os.close(devnull_fd) # Prevent a double close of these fds from __init__ on error. self._closed_child_pipe_fds = True # Wait for exec to fail or succeed; possibly raising exception errpipe_read = FileObject(errpipe_read, 'rb') data = errpipe_read.read() finally: try: if hasattr(errpipe_read, 'close'): errpipe_read.close() else: os.close(errpipe_read) except OSError: # Especially on PyPy, we sometimes see the above # `os.close(errpipe_read)` raise an OSError. # It's not entirely clear why, but it happens in # InterprocessSignalTests.test_main sometimes, which must mean # we have some sort of race condition. pass finally: errpipe_read = -1 if data != b"": self.wait() child_exception = pickle.loads(data) for fd in (p2cwrite, c2pread, errread): if fd is not None and fd != -1: os.close(fd) if isinstance(child_exception, OSError): child_exception.filename = executable if hasattr(child_exception, '_failed_chdir'): child_exception.filename = cwd if getattr(child_exception, '_failed_chuser', False): child_exception.filename = None > raise child_exception E OSError: [Errno 8] Exec format error: 'locust' /usr/lib/python3/dist-packages/gevent/subprocess.py:1838: OSError __ StandaloneIntegrationTests.test_default_headless_spawn_options_with_shape ___ self = @unittest.skipIf(sys.version_info < (3, 9), reason="dies in 3.8 on GH and I cant be bothered to investigate it") def test_default_headless_spawn_options_with_shape(self): content = MOCK_LOCUSTFILE_CONTENT + textwrap.dedent( """ class LoadTestShape(LoadTestShape): def tick(self): run_time = self.get_run_time() if run_time < 2: return (10, 1) return None """ ) with mock_locustfile(content=content) as mocked: > proc = subprocess.Popen( [ "locust", "-f", mocked.file_path, "--host", "https://test.com/", "--headless", "--exit-code-on-error", "0", ], stdout=PIPE, stderr=PIPE, text=True, ) locust/test/test_main.py:500: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3/dist-packages/gevent/subprocess.py:808: in __init__ self._execute_child(args, executable, preexec_fn, close_fds, _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = args = ['locust', '-f', '/build/reproducible-path/locust-2.24.0/locust/test/mock_locustfile_1715255800_8448427_67012.py', '--host', 'https://test.com/', '--headless', ...] executable = 'locust', preexec_fn = None, close_fds = True, pass_fds = () cwd = None, env = None, universal_newlines = None, startupinfo = None creationflags = 0, shell = False, p2cread = -1, p2cwrite = -1, c2pread = 11 c2pwrite = 80, errread = 81, errwrite = 82, restore_signals = True, gid = None gids = None, uid = None, umask = -1, start_new_session = False process_group = None def _execute_child(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, universal_newlines, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, restore_signals, gid, gids, uid, umask, start_new_session, process_group): """Execute program (POSIX version)""" if isinstance(args, (str, bytes)): args = [args] elif isinstance(args, PathLike): if shell: raise TypeError('path-like args is not allowed when ' 'shell is true') args = [fsencode(args)] # os.PathLike -> [str] else: args = list(args) if shell: # On Android the default shell is at '/system/bin/sh'. unix_shell = ( '/system/bin/sh' if hasattr(sys, 'getandroidapilevel') else '/bin/sh' ) args = [unix_shell, "-c"] + args if executable: args[0] = executable if executable is None: executable = args[0] self._loop.install_sigchld() # For transferring possible exec failure from child to parent # The first char specifies the exception type: 0 means # OSError, 1 means some other error. errpipe_read, errpipe_write = self.pipe_cloexec() # errpipe_write must not be in the standard io 0, 1, or 2 fd range. low_fds_to_close = [] while errpipe_write < 3: low_fds_to_close.append(errpipe_write) errpipe_write = os.dup(errpipe_write) for low_fd in low_fds_to_close: os.close(low_fd) try: try: gc_was_enabled = gc.isenabled() # Disable gc to avoid bug where gc -> file_dealloc -> # write to stderr -> hang. http://bugs.python.org/issue1336 gc.disable() try: self.pid = fork_and_watch(self._on_child, self._loop, True, fork) except: if gc_was_enabled: gc.enable() raise if self.pid == 0: # Child # In various places on the child side of things, we catch OSError # and add attributes to it that detail where in the process we failed; # like all exceptions until we have exec'd, this exception is pickled # and sent to the parent to raise in the calling process. # The parent uses this to decide how to treat that exception, # adjusting certain information about it as needed. # # Python 3.11.8 --- yes, a minor patch release --- stopped # letting the 'filename' parameter get set in the resulting # exception for many cases. We're not quite interpreting this # the same way the stdlib is, I'm sure, but this makes the stdlib # tests pass. # XXX: Technically we're doing a lot of stuff here that # may not be safe to do before a exec(), depending on the OS. # CPython 3 goes to great lengths to precompute a lot # of this info before the fork and pass it all to C functions that # try hard not to call things like malloc(). (Of course, # CPython 2 pretty much did what we're doing.) try: # Close parent's pipe ends if p2cwrite != -1: os.close(p2cwrite) if c2pread != -1: os.close(c2pread) if errread != -1: os.close(errread) os.close(errpipe_read) # When duping fds, if there arises a situation # where one of the fds is either 0, 1 or 2, it # is possible that it is overwritten (#12607). if c2pwrite == 0: c2pwrite = os.dup(c2pwrite) _set_inheritable(c2pwrite, False) while errwrite in (0, 1): errwrite = os.dup(errwrite) _set_inheritable(errwrite, False) # Dup fds for child def _dup2(existing, desired): # dup2() removes the CLOEXEC flag but # we must do it ourselves if dup2() # would be a no-op (issue #10806). if existing == desired: self._set_cloexec_flag(existing, False) elif existing != -1: os.dup2(existing, desired) try: self._remove_nonblock_flag(desired) except OSError: # Ignore EBADF, it may not actually be # open yet. # Tested beginning in 3.7.0b3 test_subprocess.py pass _dup2(p2cread, 0) _dup2(c2pwrite, 1) _dup2(errwrite, 2) # Close pipe fds. Make sure we don't close the # same fd more than once, or standard fds. if not True: closed = set([None]) for fd in (p2cread, c2pwrite, errwrite): if fd not in closed and fd > 2: os.close(fd) closed.add(fd) # Python 3 (with a working set_inheritable): # We no longer manually close p2cread, # c2pwrite, and errwrite here as # _close_open_fds takes care when it is # not already non-inheritable. if cwd is not None: try: os.chdir(cwd) except OSError as e: e._failed_chdir = True raise # Python 3.9 if umask >= 0: os.umask(umask) # XXX: CPython does _Py_RestoreSignals here. # Then setsid() based on ??? try: if gids: os.setgroups(gids) if gid: os.setregid(gid, gid) if uid: os.setreuid(uid, uid) if process_group is not None: os.setpgid(0, process_group) except OSError as e: e._failed_chuser = True raise if preexec_fn: preexec_fn() # Close all other fds, if asked for. This must be done # after preexec_fn runs. if close_fds: fds_to_keep = set(pass_fds) fds_to_keep.add(errpipe_write) self._close_fds(fds_to_keep, errpipe_write) if restore_signals: # restore the documented signals back to sig_dfl; # not all will be defined on every platform for sig in 'SIGPIPE', 'SIGXFZ', 'SIGXFSZ': sig = getattr(signal, sig, None) if sig is not None: signal.signal(sig, signal.SIG_DFL) if start_new_session: os.setsid() try: if env is None: os.execvp(executable, args) else: # Python 3.6 started testing for # bytes values in the env; it also # started encoding strs using # fsencode and using a lower-level # API that takes a list of keys # and values. We don't have access # to that API, so we go the reverse direction. env = {os.fsdecode(k) if isinstance(k, bytes) else k: os.fsdecode(v) if isinstance(v, bytes) else v for k, v in env.items()} os.execvpe(executable, args, env) except OSError as e: e._failed_exec = True raise except: exc_type, exc_value, tb = sys.exc_info() # Save the traceback and attach it to the exception object exc_lines = traceback.format_exception(exc_type, exc_value, tb) exc_value.child_traceback = ''.join(exc_lines) os.write(errpipe_write, pickle.dumps(exc_value)) finally: # Make sure that the process exits no matter what. # The return code does not matter much as it won't be # reported to the application os._exit(1) # Parent self._child_created = True if gc_was_enabled: gc.enable() finally: # be sure the FD is closed no matter what os.close(errpipe_write) # self._devnull is not always defined. devnull_fd = getattr(self, '_devnull', None) if p2cread != -1 and p2cwrite != -1 and p2cread != devnull_fd: os.close(p2cread) if c2pwrite != -1 and c2pread != -1 and c2pwrite != devnull_fd: os.close(c2pwrite) if errwrite != -1 and errread != -1 and errwrite != devnull_fd: os.close(errwrite) if devnull_fd is not None: os.close(devnull_fd) # Prevent a double close of these fds from __init__ on error. self._closed_child_pipe_fds = True # Wait for exec to fail or succeed; possibly raising exception errpipe_read = FileObject(errpipe_read, 'rb') data = errpipe_read.read() finally: try: if hasattr(errpipe_read, 'close'): errpipe_read.close() else: os.close(errpipe_read) except OSError: # Especially on PyPy, we sometimes see the above # `os.close(errpipe_read)` raise an OSError. # It's not entirely clear why, but it happens in # InterprocessSignalTests.test_main sometimes, which must mean # we have some sort of race condition. pass finally: errpipe_read = -1 if data != b"": self.wait() child_exception = pickle.loads(data) for fd in (p2cwrite, c2pread, errread): if fd is not None and fd != -1: os.close(fd) if isinstance(child_exception, OSError): child_exception.filename = executable if hasattr(child_exception, '_failed_chdir'): child_exception.filename = cwd if getattr(child_exception, '_failed_chuser', False): child_exception.filename = None > raise child_exception E OSError: [Errno 8] Exec format error: 'locust' /usr/lib/python3/dist-packages/gevent/subprocess.py:1838: OSError ____ StandaloneIntegrationTests.test_error_when_duplicate_shape_class_names ____ self = def test_error_when_duplicate_shape_class_names(self): MOCK_LOCUSTFILE_CONTENT_C = MOCK_LOCUSTFILE_CONTENT_A + textwrap.dedent( """ from locust import LoadTestShape class TestShape(LoadTestShape): def tick(self): run_time = self.get_run_time() if run_time < 2: return (10, 1) return None """ ) MOCK_LOCUSTFILE_CONTENT_D = MOCK_LOCUSTFILE_CONTENT_B + textwrap.dedent( """ from locust import LoadTestShape class TestShape(LoadTestShape): def tick(self): run_time = self.get_run_time() if run_time < 2: return (10, 1) return None """ ) with temporary_file(content=MOCK_LOCUSTFILE_CONTENT_C) as file1: with temporary_file(content=MOCK_LOCUSTFILE_CONTENT_D) as file2: > proc = subprocess.Popen(["locust", "-f", f"{file1},{file2}"], stdout=PIPE, stderr=PIPE, text=True) locust/test/test_main.py:1209: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3/dist-packages/gevent/subprocess.py:808: in __init__ self._execute_child(args, executable, preexec_fn, close_fds, _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = args = ['locust', '-f', '/tmp/tmpvt3m02e9_locustfile.py,/tmp/tmpemqo3j7z_locustfile.py'] executable = 'locust', preexec_fn = None, close_fds = True, pass_fds = () cwd = None, env = None, universal_newlines = None, startupinfo = None creationflags = 0, shell = False, p2cread = -1, p2cwrite = -1, c2pread = 11 c2pwrite = 80, errread = 81, errwrite = 82, restore_signals = True, gid = None gids = None, uid = None, umask = -1, start_new_session = False process_group = None def _execute_child(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, universal_newlines, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, restore_signals, gid, gids, uid, umask, start_new_session, process_group): """Execute program (POSIX version)""" if isinstance(args, (str, bytes)): args = [args] elif isinstance(args, PathLike): if shell: raise TypeError('path-like args is not allowed when ' 'shell is true') args = [fsencode(args)] # os.PathLike -> [str] else: args = list(args) if shell: # On Android the default shell is at '/system/bin/sh'. unix_shell = ( '/system/bin/sh' if hasattr(sys, 'getandroidapilevel') else '/bin/sh' ) args = [unix_shell, "-c"] + args if executable: args[0] = executable if executable is None: executable = args[0] self._loop.install_sigchld() # For transferring possible exec failure from child to parent # The first char specifies the exception type: 0 means # OSError, 1 means some other error. errpipe_read, errpipe_write = self.pipe_cloexec() # errpipe_write must not be in the standard io 0, 1, or 2 fd range. low_fds_to_close = [] while errpipe_write < 3: low_fds_to_close.append(errpipe_write) errpipe_write = os.dup(errpipe_write) for low_fd in low_fds_to_close: os.close(low_fd) try: try: gc_was_enabled = gc.isenabled() # Disable gc to avoid bug where gc -> file_dealloc -> # write to stderr -> hang. http://bugs.python.org/issue1336 gc.disable() try: self.pid = fork_and_watch(self._on_child, self._loop, True, fork) except: if gc_was_enabled: gc.enable() raise if self.pid == 0: # Child # In various places on the child side of things, we catch OSError # and add attributes to it that detail where in the process we failed; # like all exceptions until we have exec'd, this exception is pickled # and sent to the parent to raise in the calling process. # The parent uses this to decide how to treat that exception, # adjusting certain information about it as needed. # # Python 3.11.8 --- yes, a minor patch release --- stopped # letting the 'filename' parameter get set in the resulting # exception for many cases. We're not quite interpreting this # the same way the stdlib is, I'm sure, but this makes the stdlib # tests pass. # XXX: Technically we're doing a lot of stuff here that # may not be safe to do before a exec(), depending on the OS. # CPython 3 goes to great lengths to precompute a lot # of this info before the fork and pass it all to C functions that # try hard not to call things like malloc(). (Of course, # CPython 2 pretty much did what we're doing.) try: # Close parent's pipe ends if p2cwrite != -1: os.close(p2cwrite) if c2pread != -1: os.close(c2pread) if errread != -1: os.close(errread) os.close(errpipe_read) # When duping fds, if there arises a situation # where one of the fds is either 0, 1 or 2, it # is possible that it is overwritten (#12607). if c2pwrite == 0: c2pwrite = os.dup(c2pwrite) _set_inheritable(c2pwrite, False) while errwrite in (0, 1): errwrite = os.dup(errwrite) _set_inheritable(errwrite, False) # Dup fds for child def _dup2(existing, desired): # dup2() removes the CLOEXEC flag but # we must do it ourselves if dup2() # would be a no-op (issue #10806). if existing == desired: self._set_cloexec_flag(existing, False) elif existing != -1: os.dup2(existing, desired) try: self._remove_nonblock_flag(desired) except OSError: # Ignore EBADF, it may not actually be # open yet. # Tested beginning in 3.7.0b3 test_subprocess.py pass _dup2(p2cread, 0) _dup2(c2pwrite, 1) _dup2(errwrite, 2) # Close pipe fds. Make sure we don't close the # same fd more than once, or standard fds. if not True: closed = set([None]) for fd in (p2cread, c2pwrite, errwrite): if fd not in closed and fd > 2: os.close(fd) closed.add(fd) # Python 3 (with a working set_inheritable): # We no longer manually close p2cread, # c2pwrite, and errwrite here as # _close_open_fds takes care when it is # not already non-inheritable. if cwd is not None: try: os.chdir(cwd) except OSError as e: e._failed_chdir = True raise # Python 3.9 if umask >= 0: os.umask(umask) # XXX: CPython does _Py_RestoreSignals here. # Then setsid() based on ??? try: if gids: os.setgroups(gids) if gid: os.setregid(gid, gid) if uid: os.setreuid(uid, uid) if process_group is not None: os.setpgid(0, process_group) except OSError as e: e._failed_chuser = True raise if preexec_fn: preexec_fn() # Close all other fds, if asked for. This must be done # after preexec_fn runs. if close_fds: fds_to_keep = set(pass_fds) fds_to_keep.add(errpipe_write) self._close_fds(fds_to_keep, errpipe_write) if restore_signals: # restore the documented signals back to sig_dfl; # not all will be defined on every platform for sig in 'SIGPIPE', 'SIGXFZ', 'SIGXFSZ': sig = getattr(signal, sig, None) if sig is not None: signal.signal(sig, signal.SIG_DFL) if start_new_session: os.setsid() try: if env is None: os.execvp(executable, args) else: # Python 3.6 started testing for # bytes values in the env; it also # started encoding strs using # fsencode and using a lower-level # API that takes a list of keys # and values. We don't have access # to that API, so we go the reverse direction. env = {os.fsdecode(k) if isinstance(k, bytes) else k: os.fsdecode(v) if isinstance(v, bytes) else v for k, v in env.items()} os.execvpe(executable, args, env) except OSError as e: e._failed_exec = True raise except: exc_type, exc_value, tb = sys.exc_info() # Save the traceback and attach it to the exception object exc_lines = traceback.format_exception(exc_type, exc_value, tb) exc_value.child_traceback = ''.join(exc_lines) os.write(errpipe_write, pickle.dumps(exc_value)) finally: # Make sure that the process exits no matter what. # The return code does not matter much as it won't be # reported to the application os._exit(1) # Parent self._child_created = True if gc_was_enabled: gc.enable() finally: # be sure the FD is closed no matter what os.close(errpipe_write) # self._devnull is not always defined. devnull_fd = getattr(self, '_devnull', None) if p2cread != -1 and p2cwrite != -1 and p2cread != devnull_fd: os.close(p2cread) if c2pwrite != -1 and c2pread != -1 and c2pwrite != devnull_fd: os.close(c2pwrite) if errwrite != -1 and errread != -1 and errwrite != devnull_fd: os.close(errwrite) if devnull_fd is not None: os.close(devnull_fd) # Prevent a double close of these fds from __init__ on error. self._closed_child_pipe_fds = True # Wait for exec to fail or succeed; possibly raising exception errpipe_read = FileObject(errpipe_read, 'rb') data = errpipe_read.read() finally: try: if hasattr(errpipe_read, 'close'): errpipe_read.close() else: os.close(errpipe_read) except OSError: # Especially on PyPy, we sometimes see the above # `os.close(errpipe_read)` raise an OSError. # It's not entirely clear why, but it happens in # InterprocessSignalTests.test_main sometimes, which must mean # we have some sort of race condition. pass finally: errpipe_read = -1 if data != b"": self.wait() child_exception = pickle.loads(data) for fd in (p2cwrite, c2pread, errread): if fd is not None and fd != -1: os.close(fd) if isinstance(child_exception, OSError): child_exception.filename = executable if hasattr(child_exception, '_failed_chdir'): child_exception.filename = cwd if getattr(child_exception, '_failed_chuser', False): child_exception.filename = None > raise child_exception E OSError: [Errno 8] Exec format error: 'locust' /usr/lib/python3/dist-packages/gevent/subprocess.py:1838: OSError _____ StandaloneIntegrationTests.test_error_when_duplicate_userclass_names _____ self = def test_error_when_duplicate_userclass_names(self): MOCK_LOCUSTFILE_CONTENT_C = textwrap.dedent( """ from locust import User, task, constant, events class TestUser1(User): wait_time = constant(3) @task def my_task(self): print("running my_task()") """ ) with temporary_file(content=MOCK_LOCUSTFILE_CONTENT_A) as file1: with temporary_file(content=MOCK_LOCUSTFILE_CONTENT_C) as file2: > proc = subprocess.Popen(["locust", "-f", f"{file1},{file2}"], stdout=PIPE, stderr=PIPE, text=True) locust/test/test_main.py:1157: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3/dist-packages/gevent/subprocess.py:808: in __init__ self._execute_child(args, executable, preexec_fn, close_fds, _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = args = ['locust', '-f', '/tmp/tmpa6xq3bj6_locustfile.py,/tmp/tmplfhhqj2c_locustfile.py'] executable = 'locust', preexec_fn = None, close_fds = True, pass_fds = () cwd = None, env = None, universal_newlines = None, startupinfo = None creationflags = 0, shell = False, p2cread = -1, p2cwrite = -1, c2pread = 11 c2pwrite = 80, errread = 81, errwrite = 82, restore_signals = True, gid = None gids = None, uid = None, umask = -1, start_new_session = False process_group = None def _execute_child(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, universal_newlines, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, restore_signals, gid, gids, uid, umask, start_new_session, process_group): """Execute program (POSIX version)""" if isinstance(args, (str, bytes)): args = [args] elif isinstance(args, PathLike): if shell: raise TypeError('path-like args is not allowed when ' 'shell is true') args = [fsencode(args)] # os.PathLike -> [str] else: args = list(args) if shell: # On Android the default shell is at '/system/bin/sh'. unix_shell = ( '/system/bin/sh' if hasattr(sys, 'getandroidapilevel') else '/bin/sh' ) args = [unix_shell, "-c"] + args if executable: args[0] = executable if executable is None: executable = args[0] self._loop.install_sigchld() # For transferring possible exec failure from child to parent # The first char specifies the exception type: 0 means # OSError, 1 means some other error. errpipe_read, errpipe_write = self.pipe_cloexec() # errpipe_write must not be in the standard io 0, 1, or 2 fd range. low_fds_to_close = [] while errpipe_write < 3: low_fds_to_close.append(errpipe_write) errpipe_write = os.dup(errpipe_write) for low_fd in low_fds_to_close: os.close(low_fd) try: try: gc_was_enabled = gc.isenabled() # Disable gc to avoid bug where gc -> file_dealloc -> # write to stderr -> hang. http://bugs.python.org/issue1336 gc.disable() try: self.pid = fork_and_watch(self._on_child, self._loop, True, fork) except: if gc_was_enabled: gc.enable() raise if self.pid == 0: # Child # In various places on the child side of things, we catch OSError # and add attributes to it that detail where in the process we failed; # like all exceptions until we have exec'd, this exception is pickled # and sent to the parent to raise in the calling process. # The parent uses this to decide how to treat that exception, # adjusting certain information about it as needed. # # Python 3.11.8 --- yes, a minor patch release --- stopped # letting the 'filename' parameter get set in the resulting # exception for many cases. We're not quite interpreting this # the same way the stdlib is, I'm sure, but this makes the stdlib # tests pass. # XXX: Technically we're doing a lot of stuff here that # may not be safe to do before a exec(), depending on the OS. # CPython 3 goes to great lengths to precompute a lot # of this info before the fork and pass it all to C functions that # try hard not to call things like malloc(). (Of course, # CPython 2 pretty much did what we're doing.) try: # Close parent's pipe ends if p2cwrite != -1: os.close(p2cwrite) if c2pread != -1: os.close(c2pread) if errread != -1: os.close(errread) os.close(errpipe_read) # When duping fds, if there arises a situation # where one of the fds is either 0, 1 or 2, it # is possible that it is overwritten (#12607). if c2pwrite == 0: c2pwrite = os.dup(c2pwrite) _set_inheritable(c2pwrite, False) while errwrite in (0, 1): errwrite = os.dup(errwrite) _set_inheritable(errwrite, False) # Dup fds for child def _dup2(existing, desired): # dup2() removes the CLOEXEC flag but # we must do it ourselves if dup2() # would be a no-op (issue #10806). if existing == desired: self._set_cloexec_flag(existing, False) elif existing != -1: os.dup2(existing, desired) try: self._remove_nonblock_flag(desired) except OSError: # Ignore EBADF, it may not actually be # open yet. # Tested beginning in 3.7.0b3 test_subprocess.py pass _dup2(p2cread, 0) _dup2(c2pwrite, 1) _dup2(errwrite, 2) # Close pipe fds. Make sure we don't close the # same fd more than once, or standard fds. if not True: closed = set([None]) for fd in (p2cread, c2pwrite, errwrite): if fd not in closed and fd > 2: os.close(fd) closed.add(fd) # Python 3 (with a working set_inheritable): # We no longer manually close p2cread, # c2pwrite, and errwrite here as # _close_open_fds takes care when it is # not already non-inheritable. if cwd is not None: try: os.chdir(cwd) except OSError as e: e._failed_chdir = True raise # Python 3.9 if umask >= 0: os.umask(umask) # XXX: CPython does _Py_RestoreSignals here. # Then setsid() based on ??? try: if gids: os.setgroups(gids) if gid: os.setregid(gid, gid) if uid: os.setreuid(uid, uid) if process_group is not None: os.setpgid(0, process_group) except OSError as e: e._failed_chuser = True raise if preexec_fn: preexec_fn() # Close all other fds, if asked for. This must be done # after preexec_fn runs. if close_fds: fds_to_keep = set(pass_fds) fds_to_keep.add(errpipe_write) self._close_fds(fds_to_keep, errpipe_write) if restore_signals: # restore the documented signals back to sig_dfl; # not all will be defined on every platform for sig in 'SIGPIPE', 'SIGXFZ', 'SIGXFSZ': sig = getattr(signal, sig, None) if sig is not None: signal.signal(sig, signal.SIG_DFL) if start_new_session: os.setsid() try: if env is None: os.execvp(executable, args) else: # Python 3.6 started testing for # bytes values in the env; it also # started encoding strs using # fsencode and using a lower-level # API that takes a list of keys # and values. We don't have access # to that API, so we go the reverse direction. env = {os.fsdecode(k) if isinstance(k, bytes) else k: os.fsdecode(v) if isinstance(v, bytes) else v for k, v in env.items()} os.execvpe(executable, args, env) except OSError as e: e._failed_exec = True raise except: exc_type, exc_value, tb = sys.exc_info() # Save the traceback and attach it to the exception object exc_lines = traceback.format_exception(exc_type, exc_value, tb) exc_value.child_traceback = ''.join(exc_lines) os.write(errpipe_write, pickle.dumps(exc_value)) finally: # Make sure that the process exits no matter what. # The return code does not matter much as it won't be # reported to the application os._exit(1) # Parent self._child_created = True if gc_was_enabled: gc.enable() finally: # be sure the FD is closed no matter what os.close(errpipe_write) # self._devnull is not always defined. devnull_fd = getattr(self, '_devnull', None) if p2cread != -1 and p2cwrite != -1 and p2cread != devnull_fd: os.close(p2cread) if c2pwrite != -1 and c2pread != -1 and c2pwrite != devnull_fd: os.close(c2pwrite) if errwrite != -1 and errread != -1 and errwrite != devnull_fd: os.close(errwrite) if devnull_fd is not None: os.close(devnull_fd) # Prevent a double close of these fds from __init__ on error. self._closed_child_pipe_fds = True # Wait for exec to fail or succeed; possibly raising exception errpipe_read = FileObject(errpipe_read, 'rb') data = errpipe_read.read() finally: try: if hasattr(errpipe_read, 'close'): errpipe_read.close() else: os.close(errpipe_read) except OSError: # Especially on PyPy, we sometimes see the above # `os.close(errpipe_read)` raise an OSError. # It's not entirely clear why, but it happens in # InterprocessSignalTests.test_main sometimes, which must mean # we have some sort of race condition. pass finally: errpipe_read = -1 if data != b"": self.wait() child_exception = pickle.loads(data) for fd in (p2cwrite, c2pread, errread): if fd is not None and fd != -1: os.close(fd) if isinstance(child_exception, OSError): child_exception.filename = executable if hasattr(child_exception, '_failed_chdir'): child_exception.filename = cwd if getattr(child_exception, '_failed_chuser', False): child_exception.filename = None > raise child_exception E OSError: [Errno 8] Exec format error: 'locust' /usr/lib/python3/dist-packages/gevent/subprocess.py:1838: OSError __ StandaloneIntegrationTests.test_error_when_locustfiles_directory_is_empty ___ self = def test_error_when_locustfiles_directory_is_empty(self): with TemporaryDirectory() as temp_dir: > proc = subprocess.Popen(["locust", "-f", temp_dir], stdout=PIPE, stderr=PIPE, text=True) locust/test/test_main.py:1298: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3/dist-packages/gevent/subprocess.py:808: in __init__ self._execute_child(args, executable, preexec_fn, close_fds, _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = args = ['locust', '-f', '/tmp/tmpho0456n3'], executable = 'locust' preexec_fn = None, close_fds = True, pass_fds = (), cwd = None, env = None universal_newlines = None, startupinfo = None, creationflags = 0, shell = False p2cread = -1, p2cwrite = -1, c2pread = 11, c2pwrite = 80, errread = 81 errwrite = 82, restore_signals = True, gid = None, gids = None, uid = None umask = -1, start_new_session = False, process_group = None def _execute_child(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, universal_newlines, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, restore_signals, gid, gids, uid, umask, start_new_session, process_group): """Execute program (POSIX version)""" if isinstance(args, (str, bytes)): args = [args] elif isinstance(args, PathLike): if shell: raise TypeError('path-like args is not allowed when ' 'shell is true') args = [fsencode(args)] # os.PathLike -> [str] else: args = list(args) if shell: # On Android the default shell is at '/system/bin/sh'. unix_shell = ( '/system/bin/sh' if hasattr(sys, 'getandroidapilevel') else '/bin/sh' ) args = [unix_shell, "-c"] + args if executable: args[0] = executable if executable is None: executable = args[0] self._loop.install_sigchld() # For transferring possible exec failure from child to parent # The first char specifies the exception type: 0 means # OSError, 1 means some other error. errpipe_read, errpipe_write = self.pipe_cloexec() # errpipe_write must not be in the standard io 0, 1, or 2 fd range. low_fds_to_close = [] while errpipe_write < 3: low_fds_to_close.append(errpipe_write) errpipe_write = os.dup(errpipe_write) for low_fd in low_fds_to_close: os.close(low_fd) try: try: gc_was_enabled = gc.isenabled() # Disable gc to avoid bug where gc -> file_dealloc -> # write to stderr -> hang. http://bugs.python.org/issue1336 gc.disable() try: self.pid = fork_and_watch(self._on_child, self._loop, True, fork) except: if gc_was_enabled: gc.enable() raise if self.pid == 0: # Child # In various places on the child side of things, we catch OSError # and add attributes to it that detail where in the process we failed; # like all exceptions until we have exec'd, this exception is pickled # and sent to the parent to raise in the calling process. # The parent uses this to decide how to treat that exception, # adjusting certain information about it as needed. # # Python 3.11.8 --- yes, a minor patch release --- stopped # letting the 'filename' parameter get set in the resulting # exception for many cases. We're not quite interpreting this # the same way the stdlib is, I'm sure, but this makes the stdlib # tests pass. # XXX: Technically we're doing a lot of stuff here that # may not be safe to do before a exec(), depending on the OS. # CPython 3 goes to great lengths to precompute a lot # of this info before the fork and pass it all to C functions that # try hard not to call things like malloc(). (Of course, # CPython 2 pretty much did what we're doing.) try: # Close parent's pipe ends if p2cwrite != -1: os.close(p2cwrite) if c2pread != -1: os.close(c2pread) if errread != -1: os.close(errread) os.close(errpipe_read) # When duping fds, if there arises a situation # where one of the fds is either 0, 1 or 2, it # is possible that it is overwritten (#12607). if c2pwrite == 0: c2pwrite = os.dup(c2pwrite) _set_inheritable(c2pwrite, False) while errwrite in (0, 1): errwrite = os.dup(errwrite) _set_inheritable(errwrite, False) # Dup fds for child def _dup2(existing, desired): # dup2() removes the CLOEXEC flag but # we must do it ourselves if dup2() # would be a no-op (issue #10806). if existing == desired: self._set_cloexec_flag(existing, False) elif existing != -1: os.dup2(existing, desired) try: self._remove_nonblock_flag(desired) except OSError: # Ignore EBADF, it may not actually be # open yet. # Tested beginning in 3.7.0b3 test_subprocess.py pass _dup2(p2cread, 0) _dup2(c2pwrite, 1) _dup2(errwrite, 2) # Close pipe fds. Make sure we don't close the # same fd more than once, or standard fds. if not True: closed = set([None]) for fd in (p2cread, c2pwrite, errwrite): if fd not in closed and fd > 2: os.close(fd) closed.add(fd) # Python 3 (with a working set_inheritable): # We no longer manually close p2cread, # c2pwrite, and errwrite here as # _close_open_fds takes care when it is # not already non-inheritable. if cwd is not None: try: os.chdir(cwd) except OSError as e: e._failed_chdir = True raise # Python 3.9 if umask >= 0: os.umask(umask) # XXX: CPython does _Py_RestoreSignals here. # Then setsid() based on ??? try: if gids: os.setgroups(gids) if gid: os.setregid(gid, gid) if uid: os.setreuid(uid, uid) if process_group is not None: os.setpgid(0, process_group) except OSError as e: e._failed_chuser = True raise if preexec_fn: preexec_fn() # Close all other fds, if asked for. This must be done # after preexec_fn runs. if close_fds: fds_to_keep = set(pass_fds) fds_to_keep.add(errpipe_write) self._close_fds(fds_to_keep, errpipe_write) if restore_signals: # restore the documented signals back to sig_dfl; # not all will be defined on every platform for sig in 'SIGPIPE', 'SIGXFZ', 'SIGXFSZ': sig = getattr(signal, sig, None) if sig is not None: signal.signal(sig, signal.SIG_DFL) if start_new_session: os.setsid() try: if env is None: os.execvp(executable, args) else: # Python 3.6 started testing for # bytes values in the env; it also # started encoding strs using # fsencode and using a lower-level # API that takes a list of keys # and values. We don't have access # to that API, so we go the reverse direction. env = {os.fsdecode(k) if isinstance(k, bytes) else k: os.fsdecode(v) if isinstance(v, bytes) else v for k, v in env.items()} os.execvpe(executable, args, env) except OSError as e: e._failed_exec = True raise except: exc_type, exc_value, tb = sys.exc_info() # Save the traceback and attach it to the exception object exc_lines = traceback.format_exception(exc_type, exc_value, tb) exc_value.child_traceback = ''.join(exc_lines) os.write(errpipe_write, pickle.dumps(exc_value)) finally: # Make sure that the process exits no matter what. # The return code does not matter much as it won't be # reported to the application os._exit(1) # Parent self._child_created = True if gc_was_enabled: gc.enable() finally: # be sure the FD is closed no matter what os.close(errpipe_write) # self._devnull is not always defined. devnull_fd = getattr(self, '_devnull', None) if p2cread != -1 and p2cwrite != -1 and p2cread != devnull_fd: os.close(p2cread) if c2pwrite != -1 and c2pread != -1 and c2pwrite != devnull_fd: os.close(c2pwrite) if errwrite != -1 and errread != -1 and errwrite != devnull_fd: os.close(errwrite) if devnull_fd is not None: os.close(devnull_fd) # Prevent a double close of these fds from __init__ on error. self._closed_child_pipe_fds = True # Wait for exec to fail or succeed; possibly raising exception errpipe_read = FileObject(errpipe_read, 'rb') data = errpipe_read.read() finally: try: if hasattr(errpipe_read, 'close'): errpipe_read.close() else: os.close(errpipe_read) except OSError: # Especially on PyPy, we sometimes see the above # `os.close(errpipe_read)` raise an OSError. # It's not entirely clear why, but it happens in # InterprocessSignalTests.test_main sometimes, which must mean # we have some sort of race condition. pass finally: errpipe_read = -1 if data != b"": self.wait() child_exception = pickle.loads(data) for fd in (p2cwrite, c2pread, errread): if fd is not None and fd != -1: os.close(fd) if isinstance(child_exception, OSError): child_exception.filename = executable if hasattr(child_exception, '_failed_chdir'): child_exception.filename = cwd if getattr(child_exception, '_failed_chuser', False): child_exception.filename = None > raise child_exception E OSError: [Errno 8] Exec format error: 'locust' /usr/lib/python3/dist-packages/gevent/subprocess.py:1838: OSError ________ StandaloneIntegrationTests.test_error_when_no_tasks_match_tags ________ self = def test_error_when_no_tasks_match_tags(self): content = """ from locust import HttpUser, TaskSet, task, constant, LoadTestShape, tag class MyUser(HttpUser): host = "http://127.0.0.1:8089" wait_time = constant(1) @tag("tag1") @task def task1(self): print("task1") """ with mock_locustfile(content=content) as mocked: > proc = subprocess.Popen( [ "locust", "-f", mocked.file_path, "--headless", "-t", "1", "--tags", "tag2", ], stdout=PIPE, stderr=PIPE, text=True, ) locust/test/test_main.py:1317: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3/dist-packages/gevent/subprocess.py:808: in __init__ self._execute_child(args, executable, preexec_fn, close_fds, _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = args = ['locust', '-f', '/build/reproducible-path/locust-2.24.0/locust/test/mock_locustfile_1715255801_321155_79409.py', '--headless', '-t', '1', ...] executable = 'locust', preexec_fn = None, close_fds = True, pass_fds = () cwd = None, env = None, universal_newlines = None, startupinfo = None creationflags = 0, shell = False, p2cread = -1, p2cwrite = -1, c2pread = 11 c2pwrite = 80, errread = 81, errwrite = 82, restore_signals = True, gid = None gids = None, uid = None, umask = -1, start_new_session = False process_group = None def _execute_child(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, universal_newlines, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, restore_signals, gid, gids, uid, umask, start_new_session, process_group): """Execute program (POSIX version)""" if isinstance(args, (str, bytes)): args = [args] elif isinstance(args, PathLike): if shell: raise TypeError('path-like args is not allowed when ' 'shell is true') args = [fsencode(args)] # os.PathLike -> [str] else: args = list(args) if shell: # On Android the default shell is at '/system/bin/sh'. unix_shell = ( '/system/bin/sh' if hasattr(sys, 'getandroidapilevel') else '/bin/sh' ) args = [unix_shell, "-c"] + args if executable: args[0] = executable if executable is None: executable = args[0] self._loop.install_sigchld() # For transferring possible exec failure from child to parent # The first char specifies the exception type: 0 means # OSError, 1 means some other error. errpipe_read, errpipe_write = self.pipe_cloexec() # errpipe_write must not be in the standard io 0, 1, or 2 fd range. low_fds_to_close = [] while errpipe_write < 3: low_fds_to_close.append(errpipe_write) errpipe_write = os.dup(errpipe_write) for low_fd in low_fds_to_close: os.close(low_fd) try: try: gc_was_enabled = gc.isenabled() # Disable gc to avoid bug where gc -> file_dealloc -> # write to stderr -> hang. http://bugs.python.org/issue1336 gc.disable() try: self.pid = fork_and_watch(self._on_child, self._loop, True, fork) except: if gc_was_enabled: gc.enable() raise if self.pid == 0: # Child # In various places on the child side of things, we catch OSError # and add attributes to it that detail where in the process we failed; # like all exceptions until we have exec'd, this exception is pickled # and sent to the parent to raise in the calling process. # The parent uses this to decide how to treat that exception, # adjusting certain information about it as needed. # # Python 3.11.8 --- yes, a minor patch release --- stopped # letting the 'filename' parameter get set in the resulting # exception for many cases. We're not quite interpreting this # the same way the stdlib is, I'm sure, but this makes the stdlib # tests pass. # XXX: Technically we're doing a lot of stuff here that # may not be safe to do before a exec(), depending on the OS. # CPython 3 goes to great lengths to precompute a lot # of this info before the fork and pass it all to C functions that # try hard not to call things like malloc(). (Of course, # CPython 2 pretty much did what we're doing.) try: # Close parent's pipe ends if p2cwrite != -1: os.close(p2cwrite) if c2pread != -1: os.close(c2pread) if errread != -1: os.close(errread) os.close(errpipe_read) # When duping fds, if there arises a situation # where one of the fds is either 0, 1 or 2, it # is possible that it is overwritten (#12607). if c2pwrite == 0: c2pwrite = os.dup(c2pwrite) _set_inheritable(c2pwrite, False) while errwrite in (0, 1): errwrite = os.dup(errwrite) _set_inheritable(errwrite, False) # Dup fds for child def _dup2(existing, desired): # dup2() removes the CLOEXEC flag but # we must do it ourselves if dup2() # would be a no-op (issue #10806). if existing == desired: self._set_cloexec_flag(existing, False) elif existing != -1: os.dup2(existing, desired) try: self._remove_nonblock_flag(desired) except OSError: # Ignore EBADF, it may not actually be # open yet. # Tested beginning in 3.7.0b3 test_subprocess.py pass _dup2(p2cread, 0) _dup2(c2pwrite, 1) _dup2(errwrite, 2) # Close pipe fds. Make sure we don't close the # same fd more than once, or standard fds. if not True: closed = set([None]) for fd in (p2cread, c2pwrite, errwrite): if fd not in closed and fd > 2: os.close(fd) closed.add(fd) # Python 3 (with a working set_inheritable): # We no longer manually close p2cread, # c2pwrite, and errwrite here as # _close_open_fds takes care when it is # not already non-inheritable. if cwd is not None: try: os.chdir(cwd) except OSError as e: e._failed_chdir = True raise # Python 3.9 if umask >= 0: os.umask(umask) # XXX: CPython does _Py_RestoreSignals here. # Then setsid() based on ??? try: if gids: os.setgroups(gids) if gid: os.setregid(gid, gid) if uid: os.setreuid(uid, uid) if process_group is not None: os.setpgid(0, process_group) except OSError as e: e._failed_chuser = True raise if preexec_fn: preexec_fn() # Close all other fds, if asked for. This must be done # after preexec_fn runs. if close_fds: fds_to_keep = set(pass_fds) fds_to_keep.add(errpipe_write) self._close_fds(fds_to_keep, errpipe_write) if restore_signals: # restore the documented signals back to sig_dfl; # not all will be defined on every platform for sig in 'SIGPIPE', 'SIGXFZ', 'SIGXFSZ': sig = getattr(signal, sig, None) if sig is not None: signal.signal(sig, signal.SIG_DFL) if start_new_session: os.setsid() try: if env is None: os.execvp(executable, args) else: # Python 3.6 started testing for # bytes values in the env; it also # started encoding strs using # fsencode and using a lower-level # API that takes a list of keys # and values. We don't have access # to that API, so we go the reverse direction. env = {os.fsdecode(k) if isinstance(k, bytes) else k: os.fsdecode(v) if isinstance(v, bytes) else v for k, v in env.items()} os.execvpe(executable, args, env) except OSError as e: e._failed_exec = True raise except: exc_type, exc_value, tb = sys.exc_info() # Save the traceback and attach it to the exception object exc_lines = traceback.format_exception(exc_type, exc_value, tb) exc_value.child_traceback = ''.join(exc_lines) os.write(errpipe_write, pickle.dumps(exc_value)) finally: # Make sure that the process exits no matter what. # The return code does not matter much as it won't be # reported to the application os._exit(1) # Parent self._child_created = True if gc_was_enabled: gc.enable() finally: # be sure the FD is closed no matter what os.close(errpipe_write) # self._devnull is not always defined. devnull_fd = getattr(self, '_devnull', None) if p2cread != -1 and p2cwrite != -1 and p2cread != devnull_fd: os.close(p2cread) if c2pwrite != -1 and c2pread != -1 and c2pwrite != devnull_fd: os.close(c2pwrite) if errwrite != -1 and errread != -1 and errwrite != devnull_fd: os.close(errwrite) if devnull_fd is not None: os.close(devnull_fd) # Prevent a double close of these fds from __init__ on error. self._closed_child_pipe_fds = True # Wait for exec to fail or succeed; possibly raising exception errpipe_read = FileObject(errpipe_read, 'rb') data = errpipe_read.read() finally: try: if hasattr(errpipe_read, 'close'): errpipe_read.close() else: os.close(errpipe_read) except OSError: # Especially on PyPy, we sometimes see the above # `os.close(errpipe_read)` raise an OSError. # It's not entirely clear why, but it happens in # InterprocessSignalTests.test_main sometimes, which must mean # we have some sort of race condition. pass finally: errpipe_read = -1 if data != b"": self.wait() child_exception = pickle.loads(data) for fd in (p2cwrite, c2pread, errread): if fd is not None and fd != -1: os.close(fd) if isinstance(child_exception, OSError): child_exception.filename = executable if hasattr(child_exception, '_failed_chdir'): child_exception.filename = cwd if getattr(child_exception, '_failed_chuser', False): child_exception.filename = None > raise child_exception E OSError: [Errno 8] Exec format error: 'locust' /usr/lib/python3/dist-packages/gevent/subprocess.py:1838: OSError _ StandaloneIntegrationTests.test_error_when_providing_both_run_time_and_a_shape_class _ self = def test_error_when_providing_both_run_time_and_a_shape_class(self): content = MOCK_LOCUSTFILE_CONTENT + textwrap.dedent( """ from locust import LoadTestShape class TestShape(LoadTestShape): def tick(self): return None """ ) with mock_locustfile(content=content) as mocked: > out = self.assert_run( [ "locust", "-f", mocked.file_path, "--run-time=1s", "--headless", "--exit-code-on-error", "0", ] ) locust/test/test_main.py:1226: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ locust/test/test_main.py:65: in assert_run out = subprocess.run(cmd, capture_output=True, text=True, timeout=timeout) /usr/lib/python3/dist-packages/gevent/subprocess.py:2001: in run with Popen(*popenargs, **kwargs) as process: /usr/lib/python3/dist-packages/gevent/subprocess.py:808: in __init__ self._execute_child(args, executable, preexec_fn, close_fds, _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = args = ['locust', '-f', '/build/reproducible-path/locust-2.24.0/locust/test/mock_locustfile_1715255801_4364693_61395.py', '--run-time=1s', '--headless', '--exit-code-on-error', ...] executable = 'locust', preexec_fn = None, close_fds = True, pass_fds = () cwd = None, env = None, universal_newlines = None, startupinfo = None creationflags = 0, shell = False, p2cread = -1, p2cwrite = -1, c2pread = 11 c2pwrite = 80, errread = 81, errwrite = 82, restore_signals = True, gid = None gids = None, uid = None, umask = -1, start_new_session = False process_group = None def _execute_child(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, universal_newlines, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, restore_signals, gid, gids, uid, umask, start_new_session, process_group): """Execute program (POSIX version)""" if isinstance(args, (str, bytes)): args = [args] elif isinstance(args, PathLike): if shell: raise TypeError('path-like args is not allowed when ' 'shell is true') args = [fsencode(args)] # os.PathLike -> [str] else: args = list(args) if shell: # On Android the default shell is at '/system/bin/sh'. unix_shell = ( '/system/bin/sh' if hasattr(sys, 'getandroidapilevel') else '/bin/sh' ) args = [unix_shell, "-c"] + args if executable: args[0] = executable if executable is None: executable = args[0] self._loop.install_sigchld() # For transferring possible exec failure from child to parent # The first char specifies the exception type: 0 means # OSError, 1 means some other error. errpipe_read, errpipe_write = self.pipe_cloexec() # errpipe_write must not be in the standard io 0, 1, or 2 fd range. low_fds_to_close = [] while errpipe_write < 3: low_fds_to_close.append(errpipe_write) errpipe_write = os.dup(errpipe_write) for low_fd in low_fds_to_close: os.close(low_fd) try: try: gc_was_enabled = gc.isenabled() # Disable gc to avoid bug where gc -> file_dealloc -> # write to stderr -> hang. http://bugs.python.org/issue1336 gc.disable() try: self.pid = fork_and_watch(self._on_child, self._loop, True, fork) except: if gc_was_enabled: gc.enable() raise if self.pid == 0: # Child # In various places on the child side of things, we catch OSError # and add attributes to it that detail where in the process we failed; # like all exceptions until we have exec'd, this exception is pickled # and sent to the parent to raise in the calling process. # The parent uses this to decide how to treat that exception, # adjusting certain information about it as needed. # # Python 3.11.8 --- yes, a minor patch release --- stopped # letting the 'filename' parameter get set in the resulting # exception for many cases. We're not quite interpreting this # the same way the stdlib is, I'm sure, but this makes the stdlib # tests pass. # XXX: Technically we're doing a lot of stuff here that # may not be safe to do before a exec(), depending on the OS. # CPython 3 goes to great lengths to precompute a lot # of this info before the fork and pass it all to C functions that # try hard not to call things like malloc(). (Of course, # CPython 2 pretty much did what we're doing.) try: # Close parent's pipe ends if p2cwrite != -1: os.close(p2cwrite) if c2pread != -1: os.close(c2pread) if errread != -1: os.close(errread) os.close(errpipe_read) # When duping fds, if there arises a situation # where one of the fds is either 0, 1 or 2, it # is possible that it is overwritten (#12607). if c2pwrite == 0: c2pwrite = os.dup(c2pwrite) _set_inheritable(c2pwrite, False) while errwrite in (0, 1): errwrite = os.dup(errwrite) _set_inheritable(errwrite, False) # Dup fds for child def _dup2(existing, desired): # dup2() removes the CLOEXEC flag but # we must do it ourselves if dup2() # would be a no-op (issue #10806). if existing == desired: self._set_cloexec_flag(existing, False) elif existing != -1: os.dup2(existing, desired) try: self._remove_nonblock_flag(desired) except OSError: # Ignore EBADF, it may not actually be # open yet. # Tested beginning in 3.7.0b3 test_subprocess.py pass _dup2(p2cread, 0) _dup2(c2pwrite, 1) _dup2(errwrite, 2) # Close pipe fds. Make sure we don't close the # same fd more than once, or standard fds. if not True: closed = set([None]) for fd in (p2cread, c2pwrite, errwrite): if fd not in closed and fd > 2: os.close(fd) closed.add(fd) # Python 3 (with a working set_inheritable): # We no longer manually close p2cread, # c2pwrite, and errwrite here as # _close_open_fds takes care when it is # not already non-inheritable. if cwd is not None: try: os.chdir(cwd) except OSError as e: e._failed_chdir = True raise # Python 3.9 if umask >= 0: os.umask(umask) # XXX: CPython does _Py_RestoreSignals here. # Then setsid() based on ??? try: if gids: os.setgroups(gids) if gid: os.setregid(gid, gid) if uid: os.setreuid(uid, uid) if process_group is not None: os.setpgid(0, process_group) except OSError as e: e._failed_chuser = True raise if preexec_fn: preexec_fn() # Close all other fds, if asked for. This must be done # after preexec_fn runs. if close_fds: fds_to_keep = set(pass_fds) fds_to_keep.add(errpipe_write) self._close_fds(fds_to_keep, errpipe_write) if restore_signals: # restore the documented signals back to sig_dfl; # not all will be defined on every platform for sig in 'SIGPIPE', 'SIGXFZ', 'SIGXFSZ': sig = getattr(signal, sig, None) if sig is not None: signal.signal(sig, signal.SIG_DFL) if start_new_session: os.setsid() try: if env is None: os.execvp(executable, args) else: # Python 3.6 started testing for # bytes values in the env; it also # started encoding strs using # fsencode and using a lower-level # API that takes a list of keys # and values. We don't have access # to that API, so we go the reverse direction. env = {os.fsdecode(k) if isinstance(k, bytes) else k: os.fsdecode(v) if isinstance(v, bytes) else v for k, v in env.items()} os.execvpe(executable, args, env) except OSError as e: e._failed_exec = True raise except: exc_type, exc_value, tb = sys.exc_info() # Save the traceback and attach it to the exception object exc_lines = traceback.format_exception(exc_type, exc_value, tb) exc_value.child_traceback = ''.join(exc_lines) os.write(errpipe_write, pickle.dumps(exc_value)) finally: # Make sure that the process exits no matter what. # The return code does not matter much as it won't be # reported to the application os._exit(1) # Parent self._child_created = True if gc_was_enabled: gc.enable() finally: # be sure the FD is closed no matter what os.close(errpipe_write) # self._devnull is not always defined. devnull_fd = getattr(self, '_devnull', None) if p2cread != -1 and p2cwrite != -1 and p2cread != devnull_fd: os.close(p2cread) if c2pwrite != -1 and c2pread != -1 and c2pwrite != devnull_fd: os.close(c2pwrite) if errwrite != -1 and errread != -1 and errwrite != devnull_fd: os.close(errwrite) if devnull_fd is not None: os.close(devnull_fd) # Prevent a double close of these fds from __init__ on error. self._closed_child_pipe_fds = True # Wait for exec to fail or succeed; possibly raising exception errpipe_read = FileObject(errpipe_read, 'rb') data = errpipe_read.read() finally: try: if hasattr(errpipe_read, 'close'): errpipe_read.close() else: os.close(errpipe_read) except OSError: # Especially on PyPy, we sometimes see the above # `os.close(errpipe_read)` raise an OSError. # It's not entirely clear why, but it happens in # InterprocessSignalTests.test_main sometimes, which must mean # we have some sort of race condition. pass finally: errpipe_read = -1 if data != b"": self.wait() child_exception = pickle.loads(data) for fd in (p2cwrite, c2pread, errread): if fd is not None and fd != -1: os.close(fd) if isinstance(child_exception, OSError): child_exception.filename = executable if hasattr(child_exception, '_failed_chdir'): child_exception.filename = cwd if getattr(child_exception, '_failed_chuser', False): child_exception.filename = None > raise child_exception E OSError: [Errno 8] Exec format error: 'locust' /usr/lib/python3/dist-packages/gevent/subprocess.py:1838: OSError ____ StandaloneIntegrationTests.test_graceful_exit_when_keyboard_interrupt _____ self = @unittest.skipIf(os.name == "nt", reason="Signal handling on windows is hard") def test_graceful_exit_when_keyboard_interrupt(self): with temporary_file( content=textwrap.dedent( """ from locust import User, events, task, constant, LoadTestShape @events.test_stop.add_listener def on_test_stop(environment, **kwargs) -> None: print("Test Stopped") class LoadTestShape(LoadTestShape): def tick(self): run_time = self.get_run_time() if run_time < 2: return (10, 1) return None class TestUser(User): wait_time = constant(3) @task def my_task(self): print("running my_task()") """ ) ) as mocked: > proc = subprocess.Popen( [ "locust", "-f", mocked, "--headless", ], stdout=PIPE, stderr=PIPE, text=True, ) locust/test/test_main.py:1363: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3/dist-packages/gevent/subprocess.py:808: in __init__ self._execute_child(args, executable, preexec_fn, close_fds, _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = args = ['locust', '-f', '/tmp/tmpeed7v7mt_locustfile.py', '--headless'] executable = 'locust', preexec_fn = None, close_fds = True, pass_fds = () cwd = None, env = None, universal_newlines = None, startupinfo = None creationflags = 0, shell = False, p2cread = -1, p2cwrite = -1, c2pread = 11 c2pwrite = 80, errread = 81, errwrite = 82, restore_signals = True, gid = None gids = None, uid = None, umask = -1, start_new_session = False process_group = None def _execute_child(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, universal_newlines, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, restore_signals, gid, gids, uid, umask, start_new_session, process_group): """Execute program (POSIX version)""" if isinstance(args, (str, bytes)): args = [args] elif isinstance(args, PathLike): if shell: raise TypeError('path-like args is not allowed when ' 'shell is true') args = [fsencode(args)] # os.PathLike -> [str] else: args = list(args) if shell: # On Android the default shell is at '/system/bin/sh'. unix_shell = ( '/system/bin/sh' if hasattr(sys, 'getandroidapilevel') else '/bin/sh' ) args = [unix_shell, "-c"] + args if executable: args[0] = executable if executable is None: executable = args[0] self._loop.install_sigchld() # For transferring possible exec failure from child to parent # The first char specifies the exception type: 0 means # OSError, 1 means some other error. errpipe_read, errpipe_write = self.pipe_cloexec() # errpipe_write must not be in the standard io 0, 1, or 2 fd range. low_fds_to_close = [] while errpipe_write < 3: low_fds_to_close.append(errpipe_write) errpipe_write = os.dup(errpipe_write) for low_fd in low_fds_to_close: os.close(low_fd) try: try: gc_was_enabled = gc.isenabled() # Disable gc to avoid bug where gc -> file_dealloc -> # write to stderr -> hang. http://bugs.python.org/issue1336 gc.disable() try: self.pid = fork_and_watch(self._on_child, self._loop, True, fork) except: if gc_was_enabled: gc.enable() raise if self.pid == 0: # Child # In various places on the child side of things, we catch OSError # and add attributes to it that detail where in the process we failed; # like all exceptions until we have exec'd, this exception is pickled # and sent to the parent to raise in the calling process. # The parent uses this to decide how to treat that exception, # adjusting certain information about it as needed. # # Python 3.11.8 --- yes, a minor patch release --- stopped # letting the 'filename' parameter get set in the resulting # exception for many cases. We're not quite interpreting this # the same way the stdlib is, I'm sure, but this makes the stdlib # tests pass. # XXX: Technically we're doing a lot of stuff here that # may not be safe to do before a exec(), depending on the OS. # CPython 3 goes to great lengths to precompute a lot # of this info before the fork and pass it all to C functions that # try hard not to call things like malloc(). (Of course, # CPython 2 pretty much did what we're doing.) try: # Close parent's pipe ends if p2cwrite != -1: os.close(p2cwrite) if c2pread != -1: os.close(c2pread) if errread != -1: os.close(errread) os.close(errpipe_read) # When duping fds, if there arises a situation # where one of the fds is either 0, 1 or 2, it # is possible that it is overwritten (#12607). if c2pwrite == 0: c2pwrite = os.dup(c2pwrite) _set_inheritable(c2pwrite, False) while errwrite in (0, 1): errwrite = os.dup(errwrite) _set_inheritable(errwrite, False) # Dup fds for child def _dup2(existing, desired): # dup2() removes the CLOEXEC flag but # we must do it ourselves if dup2() # would be a no-op (issue #10806). if existing == desired: self._set_cloexec_flag(existing, False) elif existing != -1: os.dup2(existing, desired) try: self._remove_nonblock_flag(desired) except OSError: # Ignore EBADF, it may not actually be # open yet. # Tested beginning in 3.7.0b3 test_subprocess.py pass _dup2(p2cread, 0) _dup2(c2pwrite, 1) _dup2(errwrite, 2) # Close pipe fds. Make sure we don't close the # same fd more than once, or standard fds. if not True: closed = set([None]) for fd in (p2cread, c2pwrite, errwrite): if fd not in closed and fd > 2: os.close(fd) closed.add(fd) # Python 3 (with a working set_inheritable): # We no longer manually close p2cread, # c2pwrite, and errwrite here as # _close_open_fds takes care when it is # not already non-inheritable. if cwd is not None: try: os.chdir(cwd) except OSError as e: e._failed_chdir = True raise # Python 3.9 if umask >= 0: os.umask(umask) # XXX: CPython does _Py_RestoreSignals here. # Then setsid() based on ??? try: if gids: os.setgroups(gids) if gid: os.setregid(gid, gid) if uid: os.setreuid(uid, uid) if process_group is not None: os.setpgid(0, process_group) except OSError as e: e._failed_chuser = True raise if preexec_fn: preexec_fn() # Close all other fds, if asked for. This must be done # after preexec_fn runs. if close_fds: fds_to_keep = set(pass_fds) fds_to_keep.add(errpipe_write) self._close_fds(fds_to_keep, errpipe_write) if restore_signals: # restore the documented signals back to sig_dfl; # not all will be defined on every platform for sig in 'SIGPIPE', 'SIGXFZ', 'SIGXFSZ': sig = getattr(signal, sig, None) if sig is not None: signal.signal(sig, signal.SIG_DFL) if start_new_session: os.setsid() try: if env is None: os.execvp(executable, args) else: # Python 3.6 started testing for # bytes values in the env; it also # started encoding strs using # fsencode and using a lower-level # API that takes a list of keys # and values. We don't have access # to that API, so we go the reverse direction. env = {os.fsdecode(k) if isinstance(k, bytes) else k: os.fsdecode(v) if isinstance(v, bytes) else v for k, v in env.items()} os.execvpe(executable, args, env) except OSError as e: e._failed_exec = True raise except: exc_type, exc_value, tb = sys.exc_info() # Save the traceback and attach it to the exception object exc_lines = traceback.format_exception(exc_type, exc_value, tb) exc_value.child_traceback = ''.join(exc_lines) os.write(errpipe_write, pickle.dumps(exc_value)) finally: # Make sure that the process exits no matter what. # The return code does not matter much as it won't be # reported to the application os._exit(1) # Parent self._child_created = True if gc_was_enabled: gc.enable() finally: # be sure the FD is closed no matter what os.close(errpipe_write) # self._devnull is not always defined. devnull_fd = getattr(self, '_devnull', None) if p2cread != -1 and p2cwrite != -1 and p2cread != devnull_fd: os.close(p2cread) if c2pwrite != -1 and c2pread != -1 and c2pwrite != devnull_fd: os.close(c2pwrite) if errwrite != -1 and errread != -1 and errwrite != devnull_fd: os.close(errwrite) if devnull_fd is not None: os.close(devnull_fd) # Prevent a double close of these fds from __init__ on error. self._closed_child_pipe_fds = True # Wait for exec to fail or succeed; possibly raising exception errpipe_read = FileObject(errpipe_read, 'rb') data = errpipe_read.read() finally: try: if hasattr(errpipe_read, 'close'): errpipe_read.close() else: os.close(errpipe_read) except OSError: # Especially on PyPy, we sometimes see the above # `os.close(errpipe_read)` raise an OSError. # It's not entirely clear why, but it happens in # InterprocessSignalTests.test_main sometimes, which must mean # we have some sort of race condition. pass finally: errpipe_read = -1 if data != b"": self.wait() child_exception = pickle.loads(data) for fd in (p2cwrite, c2pread, errread): if fd is not None and fd != -1: os.close(fd) if isinstance(child_exception, OSError): child_exception.filename = executable if hasattr(child_exception, '_failed_chdir'): child_exception.filename = cwd if getattr(child_exception, '_failed_chuser', False): child_exception.filename = None > raise child_exception E OSError: [Errno 8] Exec format error: 'locust' /usr/lib/python3/dist-packages/gevent/subprocess.py:1838: OSError ______ StandaloneIntegrationTests.test_headless_spawn_options_wo_run_time ______ self = @unittest.skipIf(os.name == "nt", reason="Signal handling on windows is hard") def test_headless_spawn_options_wo_run_time(self): with mock_locustfile() as mocked: > proc = subprocess.Popen( [ "locust", "-f", mocked.file_path, "--host", "https://test.com/", "--headless", "--exit-code-on-error", "0", ], stdout=PIPE, stderr=PIPE, text=True, ) locust/test/test_main.py:421: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3/dist-packages/gevent/subprocess.py:808: in __init__ self._execute_child(args, executable, preexec_fn, close_fds, _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = args = ['locust', '-f', '/build/reproducible-path/locust-2.24.0/locust/test/mock_locustfile_1715255801_6872423_51705.py', '--host', 'https://test.com/', '--headless', ...] executable = 'locust', preexec_fn = None, close_fds = True, pass_fds = () cwd = None, env = None, universal_newlines = None, startupinfo = None creationflags = 0, shell = False, p2cread = -1, p2cwrite = -1, c2pread = 11 c2pwrite = 80, errread = 81, errwrite = 82, restore_signals = True, gid = None gids = None, uid = None, umask = -1, start_new_session = False process_group = None def _execute_child(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, universal_newlines, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, restore_signals, gid, gids, uid, umask, start_new_session, process_group): """Execute program (POSIX version)""" if isinstance(args, (str, bytes)): args = [args] elif isinstance(args, PathLike): if shell: raise TypeError('path-like args is not allowed when ' 'shell is true') args = [fsencode(args)] # os.PathLike -> [str] else: args = list(args) if shell: # On Android the default shell is at '/system/bin/sh'. unix_shell = ( '/system/bin/sh' if hasattr(sys, 'getandroidapilevel') else '/bin/sh' ) args = [unix_shell, "-c"] + args if executable: args[0] = executable if executable is None: executable = args[0] self._loop.install_sigchld() # For transferring possible exec failure from child to parent # The first char specifies the exception type: 0 means # OSError, 1 means some other error. errpipe_read, errpipe_write = self.pipe_cloexec() # errpipe_write must not be in the standard io 0, 1, or 2 fd range. low_fds_to_close = [] while errpipe_write < 3: low_fds_to_close.append(errpipe_write) errpipe_write = os.dup(errpipe_write) for low_fd in low_fds_to_close: os.close(low_fd) try: try: gc_was_enabled = gc.isenabled() # Disable gc to avoid bug where gc -> file_dealloc -> # write to stderr -> hang. http://bugs.python.org/issue1336 gc.disable() try: self.pid = fork_and_watch(self._on_child, self._loop, True, fork) except: if gc_was_enabled: gc.enable() raise if self.pid == 0: # Child # In various places on the child side of things, we catch OSError # and add attributes to it that detail where in the process we failed; # like all exceptions until we have exec'd, this exception is pickled # and sent to the parent to raise in the calling process. # The parent uses this to decide how to treat that exception, # adjusting certain information about it as needed. # # Python 3.11.8 --- yes, a minor patch release --- stopped # letting the 'filename' parameter get set in the resulting # exception for many cases. We're not quite interpreting this # the same way the stdlib is, I'm sure, but this makes the stdlib # tests pass. # XXX: Technically we're doing a lot of stuff here that # may not be safe to do before a exec(), depending on the OS. # CPython 3 goes to great lengths to precompute a lot # of this info before the fork and pass it all to C functions that # try hard not to call things like malloc(). (Of course, # CPython 2 pretty much did what we're doing.) try: # Close parent's pipe ends if p2cwrite != -1: os.close(p2cwrite) if c2pread != -1: os.close(c2pread) if errread != -1: os.close(errread) os.close(errpipe_read) # When duping fds, if there arises a situation # where one of the fds is either 0, 1 or 2, it # is possible that it is overwritten (#12607). if c2pwrite == 0: c2pwrite = os.dup(c2pwrite) _set_inheritable(c2pwrite, False) while errwrite in (0, 1): errwrite = os.dup(errwrite) _set_inheritable(errwrite, False) # Dup fds for child def _dup2(existing, desired): # dup2() removes the CLOEXEC flag but # we must do it ourselves if dup2() # would be a no-op (issue #10806). if existing == desired: self._set_cloexec_flag(existing, False) elif existing != -1: os.dup2(existing, desired) try: self._remove_nonblock_flag(desired) except OSError: # Ignore EBADF, it may not actually be # open yet. # Tested beginning in 3.7.0b3 test_subprocess.py pass _dup2(p2cread, 0) _dup2(c2pwrite, 1) _dup2(errwrite, 2) # Close pipe fds. Make sure we don't close the # same fd more than once, or standard fds. if not True: closed = set([None]) for fd in (p2cread, c2pwrite, errwrite): if fd not in closed and fd > 2: os.close(fd) closed.add(fd) # Python 3 (with a working set_inheritable): # We no longer manually close p2cread, # c2pwrite, and errwrite here as # _close_open_fds takes care when it is # not already non-inheritable. if cwd is not None: try: os.chdir(cwd) except OSError as e: e._failed_chdir = True raise # Python 3.9 if umask >= 0: os.umask(umask) # XXX: CPython does _Py_RestoreSignals here. # Then setsid() based on ??? try: if gids: os.setgroups(gids) if gid: os.setregid(gid, gid) if uid: os.setreuid(uid, uid) if process_group is not None: os.setpgid(0, process_group) except OSError as e: e._failed_chuser = True raise if preexec_fn: preexec_fn() # Close all other fds, if asked for. This must be done # after preexec_fn runs. if close_fds: fds_to_keep = set(pass_fds) fds_to_keep.add(errpipe_write) self._close_fds(fds_to_keep, errpipe_write) if restore_signals: # restore the documented signals back to sig_dfl; # not all will be defined on every platform for sig in 'SIGPIPE', 'SIGXFZ', 'SIGXFSZ': sig = getattr(signal, sig, None) if sig is not None: signal.signal(sig, signal.SIG_DFL) if start_new_session: os.setsid() try: if env is None: os.execvp(executable, args) else: # Python 3.6 started testing for # bytes values in the env; it also # started encoding strs using # fsencode and using a lower-level # API that takes a list of keys # and values. We don't have access # to that API, so we go the reverse direction. env = {os.fsdecode(k) if isinstance(k, bytes) else k: os.fsdecode(v) if isinstance(v, bytes) else v for k, v in env.items()} os.execvpe(executable, args, env) except OSError as e: e._failed_exec = True raise except: exc_type, exc_value, tb = sys.exc_info() # Save the traceback and attach it to the exception object exc_lines = traceback.format_exception(exc_type, exc_value, tb) exc_value.child_traceback = ''.join(exc_lines) os.write(errpipe_write, pickle.dumps(exc_value)) finally: # Make sure that the process exits no matter what. # The return code does not matter much as it won't be # reported to the application os._exit(1) # Parent self._child_created = True if gc_was_enabled: gc.enable() finally: # be sure the FD is closed no matter what os.close(errpipe_write) # self._devnull is not always defined. devnull_fd = getattr(self, '_devnull', None) if p2cread != -1 and p2cwrite != -1 and p2cread != devnull_fd: os.close(p2cread) if c2pwrite != -1 and c2pread != -1 and c2pwrite != devnull_fd: os.close(c2pwrite) if errwrite != -1 and errread != -1 and errwrite != devnull_fd: os.close(errwrite) if devnull_fd is not None: os.close(devnull_fd) # Prevent a double close of these fds from __init__ on error. self._closed_child_pipe_fds = True # Wait for exec to fail or succeed; possibly raising exception errpipe_read = FileObject(errpipe_read, 'rb') data = errpipe_read.read() finally: try: if hasattr(errpipe_read, 'close'): errpipe_read.close() else: os.close(errpipe_read) except OSError: # Especially on PyPy, we sometimes see the above # `os.close(errpipe_read)` raise an OSError. # It's not entirely clear why, but it happens in # InterprocessSignalTests.test_main sometimes, which must mean # we have some sort of race condition. pass finally: errpipe_read = -1 if data != b"": self.wait() child_exception = pickle.loads(data) for fd in (p2cwrite, c2pread, errread): if fd is not None and fd != -1: os.close(fd) if isinstance(child_exception, OSError): child_exception.filename = executable if hasattr(child_exception, '_failed_chdir'): child_exception.filename = cwd if getattr(child_exception, '_failed_chuser', False): child_exception.filename = None > raise child_exception E OSError: [Errno 8] Exec format error: 'locust' /usr/lib/python3/dist-packages/gevent/subprocess.py:1838: OSError ___________________ StandaloneIntegrationTests.test_help_arg ___________________ self = def test_help_arg(self): > output = subprocess.check_output( ["locust", "--help"], stderr=subprocess.STDOUT, timeout=5, text=True, ).strip() locust/test/test_main.py:72: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3/dist-packages/gevent/subprocess.py:405: in check_output with Popen(*popenargs, stdout=PIPE, **kwargs) as process: /usr/lib/python3/dist-packages/gevent/subprocess.py:808: in __init__ self._execute_child(args, executable, preexec_fn, close_fds, _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = args = ['locust', '--help'], executable = 'locust', preexec_fn = None close_fds = True, pass_fds = (), cwd = None, env = None universal_newlines = None, startupinfo = None, creationflags = 0, shell = False p2cread = -1, p2cwrite = -1, c2pread = 11, c2pwrite = 80, errread = -1 errwrite = 80, restore_signals = True, gid = None, gids = None, uid = None umask = -1, start_new_session = False, process_group = None def _execute_child(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, universal_newlines, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, restore_signals, gid, gids, uid, umask, start_new_session, process_group): """Execute program (POSIX version)""" if isinstance(args, (str, bytes)): args = [args] elif isinstance(args, PathLike): if shell: raise TypeError('path-like args is not allowed when ' 'shell is true') args = [fsencode(args)] # os.PathLike -> [str] else: args = list(args) if shell: # On Android the default shell is at '/system/bin/sh'. unix_shell = ( '/system/bin/sh' if hasattr(sys, 'getandroidapilevel') else '/bin/sh' ) args = [unix_shell, "-c"] + args if executable: args[0] = executable if executable is None: executable = args[0] self._loop.install_sigchld() # For transferring possible exec failure from child to parent # The first char specifies the exception type: 0 means # OSError, 1 means some other error. errpipe_read, errpipe_write = self.pipe_cloexec() # errpipe_write must not be in the standard io 0, 1, or 2 fd range. low_fds_to_close = [] while errpipe_write < 3: low_fds_to_close.append(errpipe_write) errpipe_write = os.dup(errpipe_write) for low_fd in low_fds_to_close: os.close(low_fd) try: try: gc_was_enabled = gc.isenabled() # Disable gc to avoid bug where gc -> file_dealloc -> # write to stderr -> hang. http://bugs.python.org/issue1336 gc.disable() try: self.pid = fork_and_watch(self._on_child, self._loop, True, fork) except: if gc_was_enabled: gc.enable() raise if self.pid == 0: # Child # In various places on the child side of things, we catch OSError # and add attributes to it that detail where in the process we failed; # like all exceptions until we have exec'd, this exception is pickled # and sent to the parent to raise in the calling process. # The parent uses this to decide how to treat that exception, # adjusting certain information about it as needed. # # Python 3.11.8 --- yes, a minor patch release --- stopped # letting the 'filename' parameter get set in the resulting # exception for many cases. We're not quite interpreting this # the same way the stdlib is, I'm sure, but this makes the stdlib # tests pass. # XXX: Technically we're doing a lot of stuff here that # may not be safe to do before a exec(), depending on the OS. # CPython 3 goes to great lengths to precompute a lot # of this info before the fork and pass it all to C functions that # try hard not to call things like malloc(). (Of course, # CPython 2 pretty much did what we're doing.) try: # Close parent's pipe ends if p2cwrite != -1: os.close(p2cwrite) if c2pread != -1: os.close(c2pread) if errread != -1: os.close(errread) os.close(errpipe_read) # When duping fds, if there arises a situation # where one of the fds is either 0, 1 or 2, it # is possible that it is overwritten (#12607). if c2pwrite == 0: c2pwrite = os.dup(c2pwrite) _set_inheritable(c2pwrite, False) while errwrite in (0, 1): errwrite = os.dup(errwrite) _set_inheritable(errwrite, False) # Dup fds for child def _dup2(existing, desired): # dup2() removes the CLOEXEC flag but # we must do it ourselves if dup2() # would be a no-op (issue #10806). if existing == desired: self._set_cloexec_flag(existing, False) elif existing != -1: os.dup2(existing, desired) try: self._remove_nonblock_flag(desired) except OSError: # Ignore EBADF, it may not actually be # open yet. # Tested beginning in 3.7.0b3 test_subprocess.py pass _dup2(p2cread, 0) _dup2(c2pwrite, 1) _dup2(errwrite, 2) # Close pipe fds. Make sure we don't close the # same fd more than once, or standard fds. if not True: closed = set([None]) for fd in (p2cread, c2pwrite, errwrite): if fd not in closed and fd > 2: os.close(fd) closed.add(fd) # Python 3 (with a working set_inheritable): # We no longer manually close p2cread, # c2pwrite, and errwrite here as # _close_open_fds takes care when it is # not already non-inheritable. if cwd is not None: try: os.chdir(cwd) except OSError as e: e._failed_chdir = True raise # Python 3.9 if umask >= 0: os.umask(umask) # XXX: CPython does _Py_RestoreSignals here. # Then setsid() based on ??? try: if gids: os.setgroups(gids) if gid: os.setregid(gid, gid) if uid: os.setreuid(uid, uid) if process_group is not None: os.setpgid(0, process_group) except OSError as e: e._failed_chuser = True raise if preexec_fn: preexec_fn() # Close all other fds, if asked for. This must be done # after preexec_fn runs. if close_fds: fds_to_keep = set(pass_fds) fds_to_keep.add(errpipe_write) self._close_fds(fds_to_keep, errpipe_write) if restore_signals: # restore the documented signals back to sig_dfl; # not all will be defined on every platform for sig in 'SIGPIPE', 'SIGXFZ', 'SIGXFSZ': sig = getattr(signal, sig, None) if sig is not None: signal.signal(sig, signal.SIG_DFL) if start_new_session: os.setsid() try: if env is None: os.execvp(executable, args) else: # Python 3.6 started testing for # bytes values in the env; it also # started encoding strs using # fsencode and using a lower-level # API that takes a list of keys # and values. We don't have access # to that API, so we go the reverse direction. env = {os.fsdecode(k) if isinstance(k, bytes) else k: os.fsdecode(v) if isinstance(v, bytes) else v for k, v in env.items()} os.execvpe(executable, args, env) except OSError as e: e._failed_exec = True raise except: exc_type, exc_value, tb = sys.exc_info() # Save the traceback and attach it to the exception object exc_lines = traceback.format_exception(exc_type, exc_value, tb) exc_value.child_traceback = ''.join(exc_lines) os.write(errpipe_write, pickle.dumps(exc_value)) finally: # Make sure that the process exits no matter what. # The return code does not matter much as it won't be # reported to the application os._exit(1) # Parent self._child_created = True if gc_was_enabled: gc.enable() finally: # be sure the FD is closed no matter what os.close(errpipe_write) # self._devnull is not always defined. devnull_fd = getattr(self, '_devnull', None) if p2cread != -1 and p2cwrite != -1 and p2cread != devnull_fd: os.close(p2cread) if c2pwrite != -1 and c2pread != -1 and c2pwrite != devnull_fd: os.close(c2pwrite) if errwrite != -1 and errread != -1 and errwrite != devnull_fd: os.close(errwrite) if devnull_fd is not None: os.close(devnull_fd) # Prevent a double close of these fds from __init__ on error. self._closed_child_pipe_fds = True # Wait for exec to fail or succeed; possibly raising exception errpipe_read = FileObject(errpipe_read, 'rb') data = errpipe_read.read() finally: try: if hasattr(errpipe_read, 'close'): errpipe_read.close() else: os.close(errpipe_read) except OSError: # Especially on PyPy, we sometimes see the above # `os.close(errpipe_read)` raise an OSError. # It's not entirely clear why, but it happens in # InterprocessSignalTests.test_main sometimes, which must mean # we have some sort of race condition. pass finally: errpipe_read = -1 if data != b"": self.wait() child_exception = pickle.loads(data) for fd in (p2cwrite, c2pread, errread): if fd is not None and fd != -1: os.close(fd) if isinstance(child_exception, OSError): child_exception.filename = executable if hasattr(child_exception, '_failed_chdir'): child_exception.filename = cwd if getattr(child_exception, '_failed_chuser', False): child_exception.filename = None > raise child_exception E OSError: [Errno 8] Exec format error: 'locust' /usr/lib/python3/dist-packages/gevent/subprocess.py:1838: OSError ______________ StandaloneIntegrationTests.test_html_report_option ______________ self = def test_html_report_option(self): with mock_locustfile() as mocked: with temporary_file("", suffix=".html") as html_report_file_path: try: > output = subprocess.check_output( [ "locust", "-f", mocked.file_path, "--legacy-ui", "--host", "https://test.com/", "--run-time", "2s", "--headless", "--exit-code-on-error", "0", "--html", html_report_file_path, ], stderr=subprocess.STDOUT, timeout=10, text=True, ).strip() locust/test/test_main.py:1088: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3/dist-packages/gevent/subprocess.py:405: in check_output with Popen(*popenargs, stdout=PIPE, **kwargs) as process: /usr/lib/python3/dist-packages/gevent/subprocess.py:808: in __init__ self._execute_child(args, executable, preexec_fn, close_fds, _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = args = ['locust', '-f', '/build/reproducible-path/locust-2.24.0/locust/test/mock_locustfile_1715255801_9866312_34732.py', '--legacy-ui', '--host', 'https://test.com/', ...] executable = 'locust', preexec_fn = None, close_fds = True, pass_fds = () cwd = None, env = None, universal_newlines = None, startupinfo = None creationflags = 0, shell = False, p2cread = -1, p2cwrite = -1, c2pread = 11 c2pwrite = 80, errread = -1, errwrite = 80, restore_signals = True, gid = None gids = None, uid = None, umask = -1, start_new_session = False process_group = None def _execute_child(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, universal_newlines, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, restore_signals, gid, gids, uid, umask, start_new_session, process_group): """Execute program (POSIX version)""" if isinstance(args, (str, bytes)): args = [args] elif isinstance(args, PathLike): if shell: raise TypeError('path-like args is not allowed when ' 'shell is true') args = [fsencode(args)] # os.PathLike -> [str] else: args = list(args) if shell: # On Android the default shell is at '/system/bin/sh'. unix_shell = ( '/system/bin/sh' if hasattr(sys, 'getandroidapilevel') else '/bin/sh' ) args = [unix_shell, "-c"] + args if executable: args[0] = executable if executable is None: executable = args[0] self._loop.install_sigchld() # For transferring possible exec failure from child to parent # The first char specifies the exception type: 0 means # OSError, 1 means some other error. errpipe_read, errpipe_write = self.pipe_cloexec() # errpipe_write must not be in the standard io 0, 1, or 2 fd range. low_fds_to_close = [] while errpipe_write < 3: low_fds_to_close.append(errpipe_write) errpipe_write = os.dup(errpipe_write) for low_fd in low_fds_to_close: os.close(low_fd) try: try: gc_was_enabled = gc.isenabled() # Disable gc to avoid bug where gc -> file_dealloc -> # write to stderr -> hang. http://bugs.python.org/issue1336 gc.disable() try: self.pid = fork_and_watch(self._on_child, self._loop, True, fork) except: if gc_was_enabled: gc.enable() raise if self.pid == 0: # Child # In various places on the child side of things, we catch OSError # and add attributes to it that detail where in the process we failed; # like all exceptions until we have exec'd, this exception is pickled # and sent to the parent to raise in the calling process. # The parent uses this to decide how to treat that exception, # adjusting certain information about it as needed. # # Python 3.11.8 --- yes, a minor patch release --- stopped # letting the 'filename' parameter get set in the resulting # exception for many cases. We're not quite interpreting this # the same way the stdlib is, I'm sure, but this makes the stdlib # tests pass. # XXX: Technically we're doing a lot of stuff here that # may not be safe to do before a exec(), depending on the OS. # CPython 3 goes to great lengths to precompute a lot # of this info before the fork and pass it all to C functions that # try hard not to call things like malloc(). (Of course, # CPython 2 pretty much did what we're doing.) try: # Close parent's pipe ends if p2cwrite != -1: os.close(p2cwrite) if c2pread != -1: os.close(c2pread) if errread != -1: os.close(errread) os.close(errpipe_read) # When duping fds, if there arises a situation # where one of the fds is either 0, 1 or 2, it # is possible that it is overwritten (#12607). if c2pwrite == 0: c2pwrite = os.dup(c2pwrite) _set_inheritable(c2pwrite, False) while errwrite in (0, 1): errwrite = os.dup(errwrite) _set_inheritable(errwrite, False) # Dup fds for child def _dup2(existing, desired): # dup2() removes the CLOEXEC flag but # we must do it ourselves if dup2() # would be a no-op (issue #10806). if existing == desired: self._set_cloexec_flag(existing, False) elif existing != -1: os.dup2(existing, desired) try: self._remove_nonblock_flag(desired) except OSError: # Ignore EBADF, it may not actually be # open yet. # Tested beginning in 3.7.0b3 test_subprocess.py pass _dup2(p2cread, 0) _dup2(c2pwrite, 1) _dup2(errwrite, 2) # Close pipe fds. Make sure we don't close the # same fd more than once, or standard fds. if not True: closed = set([None]) for fd in (p2cread, c2pwrite, errwrite): if fd not in closed and fd > 2: os.close(fd) closed.add(fd) # Python 3 (with a working set_inheritable): # We no longer manually close p2cread, # c2pwrite, and errwrite here as # _close_open_fds takes care when it is # not already non-inheritable. if cwd is not None: try: os.chdir(cwd) except OSError as e: e._failed_chdir = True raise # Python 3.9 if umask >= 0: os.umask(umask) # XXX: CPython does _Py_RestoreSignals here. # Then setsid() based on ??? try: if gids: os.setgroups(gids) if gid: os.setregid(gid, gid) if uid: os.setreuid(uid, uid) if process_group is not None: os.setpgid(0, process_group) except OSError as e: e._failed_chuser = True raise if preexec_fn: preexec_fn() # Close all other fds, if asked for. This must be done # after preexec_fn runs. if close_fds: fds_to_keep = set(pass_fds) fds_to_keep.add(errpipe_write) self._close_fds(fds_to_keep, errpipe_write) if restore_signals: # restore the documented signals back to sig_dfl; # not all will be defined on every platform for sig in 'SIGPIPE', 'SIGXFZ', 'SIGXFSZ': sig = getattr(signal, sig, None) if sig is not None: signal.signal(sig, signal.SIG_DFL) if start_new_session: os.setsid() try: if env is None: os.execvp(executable, args) else: # Python 3.6 started testing for # bytes values in the env; it also # started encoding strs using # fsencode and using a lower-level # API that takes a list of keys # and values. We don't have access # to that API, so we go the reverse direction. env = {os.fsdecode(k) if isinstance(k, bytes) else k: os.fsdecode(v) if isinstance(v, bytes) else v for k, v in env.items()} os.execvpe(executable, args, env) except OSError as e: e._failed_exec = True raise except: exc_type, exc_value, tb = sys.exc_info() # Save the traceback and attach it to the exception object exc_lines = traceback.format_exception(exc_type, exc_value, tb) exc_value.child_traceback = ''.join(exc_lines) os.write(errpipe_write, pickle.dumps(exc_value)) finally: # Make sure that the process exits no matter what. # The return code does not matter much as it won't be # reported to the application os._exit(1) # Parent self._child_created = True if gc_was_enabled: gc.enable() finally: # be sure the FD is closed no matter what os.close(errpipe_write) # self._devnull is not always defined. devnull_fd = getattr(self, '_devnull', None) if p2cread != -1 and p2cwrite != -1 and p2cread != devnull_fd: os.close(p2cread) if c2pwrite != -1 and c2pread != -1 and c2pwrite != devnull_fd: os.close(c2pwrite) if errwrite != -1 and errread != -1 and errwrite != devnull_fd: os.close(errwrite) if devnull_fd is not None: os.close(devnull_fd) # Prevent a double close of these fds from __init__ on error. self._closed_child_pipe_fds = True # Wait for exec to fail or succeed; possibly raising exception errpipe_read = FileObject(errpipe_read, 'rb') data = errpipe_read.read() finally: try: if hasattr(errpipe_read, 'close'): errpipe_read.close() else: os.close(errpipe_read) except OSError: # Especially on PyPy, we sometimes see the above # `os.close(errpipe_read)` raise an OSError. # It's not entirely clear why, but it happens in # InterprocessSignalTests.test_main sometimes, which must mean # we have some sort of race condition. pass finally: errpipe_read = -1 if data != b"": self.wait() child_exception = pickle.loads(data) for fd in (p2cwrite, c2pread, errread): if fd is not None and fd != -1: os.close(fd) if isinstance(child_exception, OSError): child_exception.filename = executable if hasattr(child_exception, '_failed_chdir'): child_exception.filename = cwd if getattr(child_exception, '_failed_chuser', False): child_exception.filename = None > raise child_exception E OSError: [Errno 8] Exec format error: 'locust' /usr/lib/python3/dist-packages/gevent/subprocess.py:1838: OSError ____________________ StandaloneIntegrationTests.test_input _____________________ self = @unittest.skipIf(os.name == "nt", reason="termios doesnt exist on windows, and thus we cannot import pty") def test_input(self): import pty LOCUSTFILE_CONTENT = textwrap.dedent( """ from locust import User, TaskSet, task, between class UserSubclass(User): wait_time = between(0.2, 0.8) @task def t(self): print("Test task is running") """ ) with mock_locustfile(content=LOCUSTFILE_CONTENT) as mocked: stdin_m, stdin_s = pty.openpty() stdin = os.fdopen(stdin_m, "wb", 0) proc = subprocess.Popen( " ".join( [ "locust", "-f", mocked.file_path, "--headless", "--run-time", "7s", "-u", "0", "--loglevel", "INFO", ] ), stderr=STDOUT, stdin=stdin_s, stdout=PIPE, shell=True, text=True, ) gevent.sleep(1) stdin.write(b"w") gevent.sleep(1) stdin.write(b"W") gevent.sleep(1) stdin.write(b"s") gevent.sleep(1) stdin.write(b"S") gevent.sleep(1) # This should not do anything since we are already at zero users stdin.write(b"S") gevent.sleep(1) output = proc.communicate()[0] stdin.close() > self.assertIn("Ramping to 1 users at a rate of 100.00 per second", output) E AssertionError: 'Ramping to 1 users at a rate of 100.00 per second' not found in '/build/reproducible-path/locust-2.24.0/debian/locust: line 2: from: command not found\n/build/reproducible-path/locust-2.24.0/debian/locust: line 5: syntax error: unexpected end of file\n' locust/test/test_main.py:922: AssertionError _________ StandaloneIntegrationTests.test_invalid_percentile_parameter _________ self = def test_invalid_percentile_parameter(self): with temporary_file( content=textwrap.dedent( """ from locust import User, task, constant, events from locust.stats import PERCENTILES_TO_CHART PERCENTILES_TO_CHART[0] = 1.2 class TestUser(User): wait_time = constant(3) @task def my_task(self): print("running my_task()") """ ) ) as file_path: > proc = subprocess.Popen(["locust", "-f", file_path, "--autostart"], stdout=PIPE, stderr=PIPE, text=True) locust/test/test_main.py:287: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3/dist-packages/gevent/subprocess.py:808: in __init__ self._execute_child(args, executable, preexec_fn, close_fds, _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = args = ['locust', '-f', '/tmp/tmpnfv_nk67_locustfile.py', '--autostart'] executable = 'locust', preexec_fn = None, close_fds = True, pass_fds = () cwd = None, env = None, universal_newlines = None, startupinfo = None creationflags = 0, shell = False, p2cread = -1, p2cwrite = -1, c2pread = 11 c2pwrite = 81, errread = 82, errwrite = 83, restore_signals = True, gid = None gids = None, uid = None, umask = -1, start_new_session = False process_group = None def _execute_child(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, universal_newlines, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, restore_signals, gid, gids, uid, umask, start_new_session, process_group): """Execute program (POSIX version)""" if isinstance(args, (str, bytes)): args = [args] elif isinstance(args, PathLike): if shell: raise TypeError('path-like args is not allowed when ' 'shell is true') args = [fsencode(args)] # os.PathLike -> [str] else: args = list(args) if shell: # On Android the default shell is at '/system/bin/sh'. unix_shell = ( '/system/bin/sh' if hasattr(sys, 'getandroidapilevel') else '/bin/sh' ) args = [unix_shell, "-c"] + args if executable: args[0] = executable if executable is None: executable = args[0] self._loop.install_sigchld() # For transferring possible exec failure from child to parent # The first char specifies the exception type: 0 means # OSError, 1 means some other error. errpipe_read, errpipe_write = self.pipe_cloexec() # errpipe_write must not be in the standard io 0, 1, or 2 fd range. low_fds_to_close = [] while errpipe_write < 3: low_fds_to_close.append(errpipe_write) errpipe_write = os.dup(errpipe_write) for low_fd in low_fds_to_close: os.close(low_fd) try: try: gc_was_enabled = gc.isenabled() # Disable gc to avoid bug where gc -> file_dealloc -> # write to stderr -> hang. http://bugs.python.org/issue1336 gc.disable() try: self.pid = fork_and_watch(self._on_child, self._loop, True, fork) except: if gc_was_enabled: gc.enable() raise if self.pid == 0: # Child # In various places on the child side of things, we catch OSError # and add attributes to it that detail where in the process we failed; # like all exceptions until we have exec'd, this exception is pickled # and sent to the parent to raise in the calling process. # The parent uses this to decide how to treat that exception, # adjusting certain information about it as needed. # # Python 3.11.8 --- yes, a minor patch release --- stopped # letting the 'filename' parameter get set in the resulting # exception for many cases. We're not quite interpreting this # the same way the stdlib is, I'm sure, but this makes the stdlib # tests pass. # XXX: Technically we're doing a lot of stuff here that # may not be safe to do before a exec(), depending on the OS. # CPython 3 goes to great lengths to precompute a lot # of this info before the fork and pass it all to C functions that # try hard not to call things like malloc(). (Of course, # CPython 2 pretty much did what we're doing.) try: # Close parent's pipe ends if p2cwrite != -1: os.close(p2cwrite) if c2pread != -1: os.close(c2pread) if errread != -1: os.close(errread) os.close(errpipe_read) # When duping fds, if there arises a situation # where one of the fds is either 0, 1 or 2, it # is possible that it is overwritten (#12607). if c2pwrite == 0: c2pwrite = os.dup(c2pwrite) _set_inheritable(c2pwrite, False) while errwrite in (0, 1): errwrite = os.dup(errwrite) _set_inheritable(errwrite, False) # Dup fds for child def _dup2(existing, desired): # dup2() removes the CLOEXEC flag but # we must do it ourselves if dup2() # would be a no-op (issue #10806). if existing == desired: self._set_cloexec_flag(existing, False) elif existing != -1: os.dup2(existing, desired) try: self._remove_nonblock_flag(desired) except OSError: # Ignore EBADF, it may not actually be # open yet. # Tested beginning in 3.7.0b3 test_subprocess.py pass _dup2(p2cread, 0) _dup2(c2pwrite, 1) _dup2(errwrite, 2) # Close pipe fds. Make sure we don't close the # same fd more than once, or standard fds. if not True: closed = set([None]) for fd in (p2cread, c2pwrite, errwrite): if fd not in closed and fd > 2: os.close(fd) closed.add(fd) # Python 3 (with a working set_inheritable): # We no longer manually close p2cread, # c2pwrite, and errwrite here as # _close_open_fds takes care when it is # not already non-inheritable. if cwd is not None: try: os.chdir(cwd) except OSError as e: e._failed_chdir = True raise # Python 3.9 if umask >= 0: os.umask(umask) # XXX: CPython does _Py_RestoreSignals here. # Then setsid() based on ??? try: if gids: os.setgroups(gids) if gid: os.setregid(gid, gid) if uid: os.setreuid(uid, uid) if process_group is not None: os.setpgid(0, process_group) except OSError as e: e._failed_chuser = True raise if preexec_fn: preexec_fn() # Close all other fds, if asked for. This must be done # after preexec_fn runs. if close_fds: fds_to_keep = set(pass_fds) fds_to_keep.add(errpipe_write) self._close_fds(fds_to_keep, errpipe_write) if restore_signals: # restore the documented signals back to sig_dfl; # not all will be defined on every platform for sig in 'SIGPIPE', 'SIGXFZ', 'SIGXFSZ': sig = getattr(signal, sig, None) if sig is not None: signal.signal(sig, signal.SIG_DFL) if start_new_session: os.setsid() try: if env is None: os.execvp(executable, args) else: # Python 3.6 started testing for # bytes values in the env; it also # started encoding strs using # fsencode and using a lower-level # API that takes a list of keys # and values. We don't have access # to that API, so we go the reverse direction. env = {os.fsdecode(k) if isinstance(k, bytes) else k: os.fsdecode(v) if isinstance(v, bytes) else v for k, v in env.items()} os.execvpe(executable, args, env) except OSError as e: e._failed_exec = True raise except: exc_type, exc_value, tb = sys.exc_info() # Save the traceback and attach it to the exception object exc_lines = traceback.format_exception(exc_type, exc_value, tb) exc_value.child_traceback = ''.join(exc_lines) os.write(errpipe_write, pickle.dumps(exc_value)) finally: # Make sure that the process exits no matter what. # The return code does not matter much as it won't be # reported to the application os._exit(1) # Parent self._child_created = True if gc_was_enabled: gc.enable() finally: # be sure the FD is closed no matter what os.close(errpipe_write) # self._devnull is not always defined. devnull_fd = getattr(self, '_devnull', None) if p2cread != -1 and p2cwrite != -1 and p2cread != devnull_fd: os.close(p2cread) if c2pwrite != -1 and c2pread != -1 and c2pwrite != devnull_fd: os.close(c2pwrite) if errwrite != -1 and errread != -1 and errwrite != devnull_fd: os.close(errwrite) if devnull_fd is not None: os.close(devnull_fd) # Prevent a double close of these fds from __init__ on error. self._closed_child_pipe_fds = True # Wait for exec to fail or succeed; possibly raising exception errpipe_read = FileObject(errpipe_read, 'rb') data = errpipe_read.read() finally: try: if hasattr(errpipe_read, 'close'): errpipe_read.close() else: os.close(errpipe_read) except OSError: # Especially on PyPy, we sometimes see the above # `os.close(errpipe_read)` raise an OSError. # It's not entirely clear why, but it happens in # InterprocessSignalTests.test_main sometimes, which must mean # we have some sort of race condition. pass finally: errpipe_read = -1 if data != b"": self.wait() child_exception = pickle.loads(data) for fd in (p2cwrite, c2pread, errread): if fd is not None and fd != -1: os.close(fd) if isinstance(child_exception, OSError): child_exception.filename = executable if hasattr(child_exception, '_failed_chdir'): child_exception.filename = cwd if getattr(child_exception, '_failed_chuser', False): child_exception.filename = None > raise child_exception E OSError: [Errno 8] Exec format error: 'locust' /usr/lib/python3/dist-packages/gevent/subprocess.py:1838: OSError _________ StandaloneIntegrationTests.test_invalid_stop_timeout_string __________ self = def test_invalid_stop_timeout_string(self): with mock_locustfile() as mocked: > proc = subprocess.Popen( [ "locust", "-f", mocked.file_path, "--host", "https://test.com/", "--stop-timeout", "asdf1", ], stdout=PIPE, stderr=PIPE, text=True, ) locust/test/test_main.py:400: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3/dist-packages/gevent/subprocess.py:808: in __init__ self._execute_child(args, executable, preexec_fn, close_fds, _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = args = ['locust', '-f', '/build/reproducible-path/locust-2.24.0/locust/test/mock_locustfile_1715255808_4625869_85731.py', '--host', 'https://test.com/', '--stop-timeout', ...] executable = 'locust', preexec_fn = None, close_fds = True, pass_fds = () cwd = None, env = None, universal_newlines = None, startupinfo = None creationflags = 0, shell = False, p2cread = -1, p2cwrite = -1, c2pread = 11 c2pwrite = 81, errread = 82, errwrite = 83, restore_signals = True, gid = None gids = None, uid = None, umask = -1, start_new_session = False process_group = None def _execute_child(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, universal_newlines, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, restore_signals, gid, gids, uid, umask, start_new_session, process_group): """Execute program (POSIX version)""" if isinstance(args, (str, bytes)): args = [args] elif isinstance(args, PathLike): if shell: raise TypeError('path-like args is not allowed when ' 'shell is true') args = [fsencode(args)] # os.PathLike -> [str] else: args = list(args) if shell: # On Android the default shell is at '/system/bin/sh'. unix_shell = ( '/system/bin/sh' if hasattr(sys, 'getandroidapilevel') else '/bin/sh' ) args = [unix_shell, "-c"] + args if executable: args[0] = executable if executable is None: executable = args[0] self._loop.install_sigchld() # For transferring possible exec failure from child to parent # The first char specifies the exception type: 0 means # OSError, 1 means some other error. errpipe_read, errpipe_write = self.pipe_cloexec() # errpipe_write must not be in the standard io 0, 1, or 2 fd range. low_fds_to_close = [] while errpipe_write < 3: low_fds_to_close.append(errpipe_write) errpipe_write = os.dup(errpipe_write) for low_fd in low_fds_to_close: os.close(low_fd) try: try: gc_was_enabled = gc.isenabled() # Disable gc to avoid bug where gc -> file_dealloc -> # write to stderr -> hang. http://bugs.python.org/issue1336 gc.disable() try: self.pid = fork_and_watch(self._on_child, self._loop, True, fork) except: if gc_was_enabled: gc.enable() raise if self.pid == 0: # Child # In various places on the child side of things, we catch OSError # and add attributes to it that detail where in the process we failed; # like all exceptions until we have exec'd, this exception is pickled # and sent to the parent to raise in the calling process. # The parent uses this to decide how to treat that exception, # adjusting certain information about it as needed. # # Python 3.11.8 --- yes, a minor patch release --- stopped # letting the 'filename' parameter get set in the resulting # exception for many cases. We're not quite interpreting this # the same way the stdlib is, I'm sure, but this makes the stdlib # tests pass. # XXX: Technically we're doing a lot of stuff here that # may not be safe to do before a exec(), depending on the OS. # CPython 3 goes to great lengths to precompute a lot # of this info before the fork and pass it all to C functions that # try hard not to call things like malloc(). (Of course, # CPython 2 pretty much did what we're doing.) try: # Close parent's pipe ends if p2cwrite != -1: os.close(p2cwrite) if c2pread != -1: os.close(c2pread) if errread != -1: os.close(errread) os.close(errpipe_read) # When duping fds, if there arises a situation # where one of the fds is either 0, 1 or 2, it # is possible that it is overwritten (#12607). if c2pwrite == 0: c2pwrite = os.dup(c2pwrite) _set_inheritable(c2pwrite, False) while errwrite in (0, 1): errwrite = os.dup(errwrite) _set_inheritable(errwrite, False) # Dup fds for child def _dup2(existing, desired): # dup2() removes the CLOEXEC flag but # we must do it ourselves if dup2() # would be a no-op (issue #10806). if existing == desired: self._set_cloexec_flag(existing, False) elif existing != -1: os.dup2(existing, desired) try: self._remove_nonblock_flag(desired) except OSError: # Ignore EBADF, it may not actually be # open yet. # Tested beginning in 3.7.0b3 test_subprocess.py pass _dup2(p2cread, 0) _dup2(c2pwrite, 1) _dup2(errwrite, 2) # Close pipe fds. Make sure we don't close the # same fd more than once, or standard fds. if not True: closed = set([None]) for fd in (p2cread, c2pwrite, errwrite): if fd not in closed and fd > 2: os.close(fd) closed.add(fd) # Python 3 (with a working set_inheritable): # We no longer manually close p2cread, # c2pwrite, and errwrite here as # _close_open_fds takes care when it is # not already non-inheritable. if cwd is not None: try: os.chdir(cwd) except OSError as e: e._failed_chdir = True raise # Python 3.9 if umask >= 0: os.umask(umask) # XXX: CPython does _Py_RestoreSignals here. # Then setsid() based on ??? try: if gids: os.setgroups(gids) if gid: os.setregid(gid, gid) if uid: os.setreuid(uid, uid) if process_group is not None: os.setpgid(0, process_group) except OSError as e: e._failed_chuser = True raise if preexec_fn: preexec_fn() # Close all other fds, if asked for. This must be done # after preexec_fn runs. if close_fds: fds_to_keep = set(pass_fds) fds_to_keep.add(errpipe_write) self._close_fds(fds_to_keep, errpipe_write) if restore_signals: # restore the documented signals back to sig_dfl; # not all will be defined on every platform for sig in 'SIGPIPE', 'SIGXFZ', 'SIGXFSZ': sig = getattr(signal, sig, None) if sig is not None: signal.signal(sig, signal.SIG_DFL) if start_new_session: os.setsid() try: if env is None: os.execvp(executable, args) else: # Python 3.6 started testing for # bytes values in the env; it also # started encoding strs using # fsencode and using a lower-level # API that takes a list of keys # and values. We don't have access # to that API, so we go the reverse direction. env = {os.fsdecode(k) if isinstance(k, bytes) else k: os.fsdecode(v) if isinstance(v, bytes) else v for k, v in env.items()} os.execvpe(executable, args, env) except OSError as e: e._failed_exec = True raise except: exc_type, exc_value, tb = sys.exc_info() # Save the traceback and attach it to the exception object exc_lines = traceback.format_exception(exc_type, exc_value, tb) exc_value.child_traceback = ''.join(exc_lines) os.write(errpipe_write, pickle.dumps(exc_value)) finally: # Make sure that the process exits no matter what. # The return code does not matter much as it won't be # reported to the application os._exit(1) # Parent self._child_created = True if gc_was_enabled: gc.enable() finally: # be sure the FD is closed no matter what os.close(errpipe_write) # self._devnull is not always defined. devnull_fd = getattr(self, '_devnull', None) if p2cread != -1 and p2cwrite != -1 and p2cread != devnull_fd: os.close(p2cread) if c2pwrite != -1 and c2pread != -1 and c2pwrite != devnull_fd: os.close(c2pwrite) if errwrite != -1 and errread != -1 and errwrite != devnull_fd: os.close(errwrite) if devnull_fd is not None: os.close(devnull_fd) # Prevent a double close of these fds from __init__ on error. self._closed_child_pipe_fds = True # Wait for exec to fail or succeed; possibly raising exception errpipe_read = FileObject(errpipe_read, 'rb') data = errpipe_read.read() finally: try: if hasattr(errpipe_read, 'close'): errpipe_read.close() else: os.close(errpipe_read) except OSError: # Especially on PyPy, we sometimes see the above # `os.close(errpipe_read)` raise an OSError. # It's not entirely clear why, but it happens in # InterprocessSignalTests.test_main sometimes, which must mean # we have some sort of race condition. pass finally: errpipe_read = -1 if data != b"": self.wait() child_exception = pickle.loads(data) for fd in (p2cwrite, c2pread, errread): if fd is not None and fd != -1: os.close(fd) if isinstance(child_exception, OSError): child_exception.filename = executable if hasattr(child_exception, '_failed_chdir'): child_exception.filename = cwd if getattr(child_exception, '_failed_chuser', False): child_exception.filename = None > raise child_exception E OSError: [Errno 8] Exec format error: 'locust' /usr/lib/python3/dist-packages/gevent/subprocess.py:1838: OSError __ StandaloneIntegrationTests.test_no_error_when_same_userclass_in_two_files ___ self = def test_no_error_when_same_userclass_in_two_files(self): with temporary_file(content=MOCK_LOCUSTFILE_CONTENT_A) as file1: MOCK_LOCUSTFILE_CONTENT_C = textwrap.dedent( f""" from {os.path.basename(file1)[:-3]} import TestUser1 """ ) print(MOCK_LOCUSTFILE_CONTENT_C) with temporary_file(content=MOCK_LOCUSTFILE_CONTENT_C) as file2: > proc = subprocess.Popen( ["locust", "-f", f"{file1},{file2}", "-t", "1", "--headless"], stdout=PIPE, stderr=PIPE, text=True ) locust/test/test_main.py:1173: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3/dist-packages/gevent/subprocess.py:808: in __init__ self._execute_child(args, executable, preexec_fn, close_fds, _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = args = ['locust', '-f', '/tmp/tmpstmci76h_locustfile.py,/tmp/tmplxeowfbh_locustfile.py', '-t', '1', '--headless'] executable = 'locust', preexec_fn = None, close_fds = True, pass_fds = () cwd = None, env = None, universal_newlines = None, startupinfo = None creationflags = 0, shell = False, p2cread = -1, p2cwrite = -1, c2pread = 11 c2pwrite = 81, errread = 82, errwrite = 83, restore_signals = True, gid = None gids = None, uid = None, umask = -1, start_new_session = False process_group = None def _execute_child(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, universal_newlines, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, restore_signals, gid, gids, uid, umask, start_new_session, process_group): """Execute program (POSIX version)""" if isinstance(args, (str, bytes)): args = [args] elif isinstance(args, PathLike): if shell: raise TypeError('path-like args is not allowed when ' 'shell is true') args = [fsencode(args)] # os.PathLike -> [str] else: args = list(args) if shell: # On Android the default shell is at '/system/bin/sh'. unix_shell = ( '/system/bin/sh' if hasattr(sys, 'getandroidapilevel') else '/bin/sh' ) args = [unix_shell, "-c"] + args if executable: args[0] = executable if executable is None: executable = args[0] self._loop.install_sigchld() # For transferring possible exec failure from child to parent # The first char specifies the exception type: 0 means # OSError, 1 means some other error. errpipe_read, errpipe_write = self.pipe_cloexec() # errpipe_write must not be in the standard io 0, 1, or 2 fd range. low_fds_to_close = [] while errpipe_write < 3: low_fds_to_close.append(errpipe_write) errpipe_write = os.dup(errpipe_write) for low_fd in low_fds_to_close: os.close(low_fd) try: try: gc_was_enabled = gc.isenabled() # Disable gc to avoid bug where gc -> file_dealloc -> # write to stderr -> hang. http://bugs.python.org/issue1336 gc.disable() try: self.pid = fork_and_watch(self._on_child, self._loop, True, fork) except: if gc_was_enabled: gc.enable() raise if self.pid == 0: # Child # In various places on the child side of things, we catch OSError # and add attributes to it that detail where in the process we failed; # like all exceptions until we have exec'd, this exception is pickled # and sent to the parent to raise in the calling process. # The parent uses this to decide how to treat that exception, # adjusting certain information about it as needed. # # Python 3.11.8 --- yes, a minor patch release --- stopped # letting the 'filename' parameter get set in the resulting # exception for many cases. We're not quite interpreting this # the same way the stdlib is, I'm sure, but this makes the stdlib # tests pass. # XXX: Technically we're doing a lot of stuff here that # may not be safe to do before a exec(), depending on the OS. # CPython 3 goes to great lengths to precompute a lot # of this info before the fork and pass it all to C functions that # try hard not to call things like malloc(). (Of course, # CPython 2 pretty much did what we're doing.) try: # Close parent's pipe ends if p2cwrite != -1: os.close(p2cwrite) if c2pread != -1: os.close(c2pread) if errread != -1: os.close(errread) os.close(errpipe_read) # When duping fds, if there arises a situation # where one of the fds is either 0, 1 or 2, it # is possible that it is overwritten (#12607). if c2pwrite == 0: c2pwrite = os.dup(c2pwrite) _set_inheritable(c2pwrite, False) while errwrite in (0, 1): errwrite = os.dup(errwrite) _set_inheritable(errwrite, False) # Dup fds for child def _dup2(existing, desired): # dup2() removes the CLOEXEC flag but # we must do it ourselves if dup2() # would be a no-op (issue #10806). if existing == desired: self._set_cloexec_flag(existing, False) elif existing != -1: os.dup2(existing, desired) try: self._remove_nonblock_flag(desired) except OSError: # Ignore EBADF, it may not actually be # open yet. # Tested beginning in 3.7.0b3 test_subprocess.py pass _dup2(p2cread, 0) _dup2(c2pwrite, 1) _dup2(errwrite, 2) # Close pipe fds. Make sure we don't close the # same fd more than once, or standard fds. if not True: closed = set([None]) for fd in (p2cread, c2pwrite, errwrite): if fd not in closed and fd > 2: os.close(fd) closed.add(fd) # Python 3 (with a working set_inheritable): # We no longer manually close p2cread, # c2pwrite, and errwrite here as # _close_open_fds takes care when it is # not already non-inheritable. if cwd is not None: try: os.chdir(cwd) except OSError as e: e._failed_chdir = True raise # Python 3.9 if umask >= 0: os.umask(umask) # XXX: CPython does _Py_RestoreSignals here. # Then setsid() based on ??? try: if gids: os.setgroups(gids) if gid: os.setregid(gid, gid) if uid: os.setreuid(uid, uid) if process_group is not None: os.setpgid(0, process_group) except OSError as e: e._failed_chuser = True raise if preexec_fn: preexec_fn() # Close all other fds, if asked for. This must be done # after preexec_fn runs. if close_fds: fds_to_keep = set(pass_fds) fds_to_keep.add(errpipe_write) self._close_fds(fds_to_keep, errpipe_write) if restore_signals: # restore the documented signals back to sig_dfl; # not all will be defined on every platform for sig in 'SIGPIPE', 'SIGXFZ', 'SIGXFSZ': sig = getattr(signal, sig, None) if sig is not None: signal.signal(sig, signal.SIG_DFL) if start_new_session: os.setsid() try: if env is None: os.execvp(executable, args) else: # Python 3.6 started testing for # bytes values in the env; it also # started encoding strs using # fsencode and using a lower-level # API that takes a list of keys # and values. We don't have access # to that API, so we go the reverse direction. env = {os.fsdecode(k) if isinstance(k, bytes) else k: os.fsdecode(v) if isinstance(v, bytes) else v for k, v in env.items()} os.execvpe(executable, args, env) except OSError as e: e._failed_exec = True raise except: exc_type, exc_value, tb = sys.exc_info() # Save the traceback and attach it to the exception object exc_lines = traceback.format_exception(exc_type, exc_value, tb) exc_value.child_traceback = ''.join(exc_lines) os.write(errpipe_write, pickle.dumps(exc_value)) finally: # Make sure that the process exits no matter what. # The return code does not matter much as it won't be # reported to the application os._exit(1) # Parent self._child_created = True if gc_was_enabled: gc.enable() finally: # be sure the FD is closed no matter what os.close(errpipe_write) # self._devnull is not always defined. devnull_fd = getattr(self, '_devnull', None) if p2cread != -1 and p2cwrite != -1 and p2cread != devnull_fd: os.close(p2cread) if c2pwrite != -1 and c2pread != -1 and c2pwrite != devnull_fd: os.close(c2pwrite) if errwrite != -1 and errread != -1 and errwrite != devnull_fd: os.close(errwrite) if devnull_fd is not None: os.close(devnull_fd) # Prevent a double close of these fds from __init__ on error. self._closed_child_pipe_fds = True # Wait for exec to fail or succeed; possibly raising exception errpipe_read = FileObject(errpipe_read, 'rb') data = errpipe_read.read() finally: try: if hasattr(errpipe_read, 'close'): errpipe_read.close() else: os.close(errpipe_read) except OSError: # Especially on PyPy, we sometimes see the above # `os.close(errpipe_read)` raise an OSError. # It's not entirely clear why, but it happens in # InterprocessSignalTests.test_main sometimes, which must mean # we have some sort of race condition. pass finally: errpipe_read = -1 if data != b"": self.wait() child_exception = pickle.loads(data) for fd in (p2cwrite, c2pread, errread): if fd is not None and fd != -1: os.close(fd) if isinstance(child_exception, OSError): child_exception.filename = executable if hasattr(child_exception, '_failed_chdir'): child_exception.filename = cwd if getattr(child_exception, '_failed_chuser', False): child_exception.filename = None > raise child_exception E OSError: [Errno 8] Exec format error: 'locust' /usr/lib/python3/dist-packages/gevent/subprocess.py:1838: OSError ----------------------------- Captured stdout call ----------------------------- from tmpstmci76h_locustfile import TestUser1 _____________ StandaloneIntegrationTests.test_percentile_parameter _____________ self = def test_percentile_parameter(self): port = get_free_tcp_port() with temporary_file( content=textwrap.dedent( """ from locust import User, task, constant, events from locust.stats import PERCENTILES_TO_CHART PERCENTILES_TO_CHART[0] = 0.9 PERCENTILES_TO_CHART[1] = 0.4 class TestUser(User): wait_time = constant(3) @task def my_task(self): print("running my_task()") """ ) ) as file_path: > proc = subprocess.Popen( ["locust", "-f", file_path, "--web-port", str(port), "--autostart"], stdout=PIPE, stderr=PIPE, text=True ) locust/test/test_main.py:233: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3/dist-packages/gevent/subprocess.py:808: in __init__ self._execute_child(args, executable, preexec_fn, close_fds, _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = args = ['locust', '-f', '/tmp/tmpklg3y54l_locustfile.py', '--web-port', '55069', '--autostart'] executable = 'locust', preexec_fn = None, close_fds = True, pass_fds = () cwd = None, env = None, universal_newlines = None, startupinfo = None creationflags = 0, shell = False, p2cread = -1, p2cwrite = -1, c2pread = 11 c2pwrite = 81, errread = 82, errwrite = 83, restore_signals = True, gid = None gids = None, uid = None, umask = -1, start_new_session = False process_group = None def _execute_child(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, universal_newlines, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, restore_signals, gid, gids, uid, umask, start_new_session, process_group): """Execute program (POSIX version)""" if isinstance(args, (str, bytes)): args = [args] elif isinstance(args, PathLike): if shell: raise TypeError('path-like args is not allowed when ' 'shell is true') args = [fsencode(args)] # os.PathLike -> [str] else: args = list(args) if shell: # On Android the default shell is at '/system/bin/sh'. unix_shell = ( '/system/bin/sh' if hasattr(sys, 'getandroidapilevel') else '/bin/sh' ) args = [unix_shell, "-c"] + args if executable: args[0] = executable if executable is None: executable = args[0] self._loop.install_sigchld() # For transferring possible exec failure from child to parent # The first char specifies the exception type: 0 means # OSError, 1 means some other error. errpipe_read, errpipe_write = self.pipe_cloexec() # errpipe_write must not be in the standard io 0, 1, or 2 fd range. low_fds_to_close = [] while errpipe_write < 3: low_fds_to_close.append(errpipe_write) errpipe_write = os.dup(errpipe_write) for low_fd in low_fds_to_close: os.close(low_fd) try: try: gc_was_enabled = gc.isenabled() # Disable gc to avoid bug where gc -> file_dealloc -> # write to stderr -> hang. http://bugs.python.org/issue1336 gc.disable() try: self.pid = fork_and_watch(self._on_child, self._loop, True, fork) except: if gc_was_enabled: gc.enable() raise if self.pid == 0: # Child # In various places on the child side of things, we catch OSError # and add attributes to it that detail where in the process we failed; # like all exceptions until we have exec'd, this exception is pickled # and sent to the parent to raise in the calling process. # The parent uses this to decide how to treat that exception, # adjusting certain information about it as needed. # # Python 3.11.8 --- yes, a minor patch release --- stopped # letting the 'filename' parameter get set in the resulting # exception for many cases. We're not quite interpreting this # the same way the stdlib is, I'm sure, but this makes the stdlib # tests pass. # XXX: Technically we're doing a lot of stuff here that # may not be safe to do before a exec(), depending on the OS. # CPython 3 goes to great lengths to precompute a lot # of this info before the fork and pass it all to C functions that # try hard not to call things like malloc(). (Of course, # CPython 2 pretty much did what we're doing.) try: # Close parent's pipe ends if p2cwrite != -1: os.close(p2cwrite) if c2pread != -1: os.close(c2pread) if errread != -1: os.close(errread) os.close(errpipe_read) # When duping fds, if there arises a situation # where one of the fds is either 0, 1 or 2, it # is possible that it is overwritten (#12607). if c2pwrite == 0: c2pwrite = os.dup(c2pwrite) _set_inheritable(c2pwrite, False) while errwrite in (0, 1): errwrite = os.dup(errwrite) _set_inheritable(errwrite, False) # Dup fds for child def _dup2(existing, desired): # dup2() removes the CLOEXEC flag but # we must do it ourselves if dup2() # would be a no-op (issue #10806). if existing == desired: self._set_cloexec_flag(existing, False) elif existing != -1: os.dup2(existing, desired) try: self._remove_nonblock_flag(desired) except OSError: # Ignore EBADF, it may not actually be # open yet. # Tested beginning in 3.7.0b3 test_subprocess.py pass _dup2(p2cread, 0) _dup2(c2pwrite, 1) _dup2(errwrite, 2) # Close pipe fds. Make sure we don't close the # same fd more than once, or standard fds. if not True: closed = set([None]) for fd in (p2cread, c2pwrite, errwrite): if fd not in closed and fd > 2: os.close(fd) closed.add(fd) # Python 3 (with a working set_inheritable): # We no longer manually close p2cread, # c2pwrite, and errwrite here as # _close_open_fds takes care when it is # not already non-inheritable. if cwd is not None: try: os.chdir(cwd) except OSError as e: e._failed_chdir = True raise # Python 3.9 if umask >= 0: os.umask(umask) # XXX: CPython does _Py_RestoreSignals here. # Then setsid() based on ??? try: if gids: os.setgroups(gids) if gid: os.setregid(gid, gid) if uid: os.setreuid(uid, uid) if process_group is not None: os.setpgid(0, process_group) except OSError as e: e._failed_chuser = True raise if preexec_fn: preexec_fn() # Close all other fds, if asked for. This must be done # after preexec_fn runs. if close_fds: fds_to_keep = set(pass_fds) fds_to_keep.add(errpipe_write) self._close_fds(fds_to_keep, errpipe_write) if restore_signals: # restore the documented signals back to sig_dfl; # not all will be defined on every platform for sig in 'SIGPIPE', 'SIGXFZ', 'SIGXFSZ': sig = getattr(signal, sig, None) if sig is not None: signal.signal(sig, signal.SIG_DFL) if start_new_session: os.setsid() try: if env is None: os.execvp(executable, args) else: # Python 3.6 started testing for # bytes values in the env; it also # started encoding strs using # fsencode and using a lower-level # API that takes a list of keys # and values. We don't have access # to that API, so we go the reverse direction. env = {os.fsdecode(k) if isinstance(k, bytes) else k: os.fsdecode(v) if isinstance(v, bytes) else v for k, v in env.items()} os.execvpe(executable, args, env) except OSError as e: e._failed_exec = True raise except: exc_type, exc_value, tb = sys.exc_info() # Save the traceback and attach it to the exception object exc_lines = traceback.format_exception(exc_type, exc_value, tb) exc_value.child_traceback = ''.join(exc_lines) os.write(errpipe_write, pickle.dumps(exc_value)) finally: # Make sure that the process exits no matter what. # The return code does not matter much as it won't be # reported to the application os._exit(1) # Parent self._child_created = True if gc_was_enabled: gc.enable() finally: # be sure the FD is closed no matter what os.close(errpipe_write) # self._devnull is not always defined. devnull_fd = getattr(self, '_devnull', None) if p2cread != -1 and p2cwrite != -1 and p2cread != devnull_fd: os.close(p2cread) if c2pwrite != -1 and c2pread != -1 and c2pwrite != devnull_fd: os.close(c2pwrite) if errwrite != -1 and errread != -1 and errwrite != devnull_fd: os.close(errwrite) if devnull_fd is not None: os.close(devnull_fd) # Prevent a double close of these fds from __init__ on error. self._closed_child_pipe_fds = True # Wait for exec to fail or succeed; possibly raising exception errpipe_read = FileObject(errpipe_read, 'rb') data = errpipe_read.read() finally: try: if hasattr(errpipe_read, 'close'): errpipe_read.close() else: os.close(errpipe_read) except OSError: # Especially on PyPy, we sometimes see the above # `os.close(errpipe_read)` raise an OSError. # It's not entirely clear why, but it happens in # InterprocessSignalTests.test_main sometimes, which must mean # we have some sort of race condition. pass finally: errpipe_read = -1 if data != b"": self.wait() child_exception = pickle.loads(data) for fd in (p2cwrite, c2pread, errread): if fd is not None and fd != -1: os.close(fd) if isinstance(child_exception, OSError): child_exception.filename = executable if hasattr(child_exception, '_failed_chdir'): child_exception.filename = cwd if getattr(child_exception, '_failed_chuser', False): child_exception.filename = None > raise child_exception E OSError: [Errno 8] Exec format error: 'locust' /usr/lib/python3/dist-packages/gevent/subprocess.py:1838: OSError __________ StandaloneIntegrationTests.test_percentiles_to_statistics ___________ self = def test_percentiles_to_statistics(self): port = get_free_tcp_port() with temporary_file( content=textwrap.dedent( """ from locust import User, task, constant, events from locust.stats import PERCENTILES_TO_STATISTICS PERCENTILES_TO_STATISTICS = [0.9, 0.99] class TestUser(User): wait_time = constant(3) @task def my_task(self): print("running my_task()") """ ) ) as file_path: > proc = subprocess.Popen( ["locust", "-f", file_path, "--web-port", str(port), "--autostart"], stdout=PIPE, stderr=PIPE, text=True, ) locust/test/test_main.py:259: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3/dist-packages/gevent/subprocess.py:808: in __init__ self._execute_child(args, executable, preexec_fn, close_fds, _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = args = ['locust', '-f', '/tmp/tmpgxv6m6pc_locustfile.py', '--web-port', '45205', '--autostart'] executable = 'locust', preexec_fn = None, close_fds = True, pass_fds = () cwd = None, env = None, universal_newlines = None, startupinfo = None creationflags = 0, shell = False, p2cread = -1, p2cwrite = -1, c2pread = 11 c2pwrite = 81, errread = 82, errwrite = 83, restore_signals = True, gid = None gids = None, uid = None, umask = -1, start_new_session = False process_group = None def _execute_child(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, universal_newlines, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, restore_signals, gid, gids, uid, umask, start_new_session, process_group): """Execute program (POSIX version)""" if isinstance(args, (str, bytes)): args = [args] elif isinstance(args, PathLike): if shell: raise TypeError('path-like args is not allowed when ' 'shell is true') args = [fsencode(args)] # os.PathLike -> [str] else: args = list(args) if shell: # On Android the default shell is at '/system/bin/sh'. unix_shell = ( '/system/bin/sh' if hasattr(sys, 'getandroidapilevel') else '/bin/sh' ) args = [unix_shell, "-c"] + args if executable: args[0] = executable if executable is None: executable = args[0] self._loop.install_sigchld() # For transferring possible exec failure from child to parent # The first char specifies the exception type: 0 means # OSError, 1 means some other error. errpipe_read, errpipe_write = self.pipe_cloexec() # errpipe_write must not be in the standard io 0, 1, or 2 fd range. low_fds_to_close = [] while errpipe_write < 3: low_fds_to_close.append(errpipe_write) errpipe_write = os.dup(errpipe_write) for low_fd in low_fds_to_close: os.close(low_fd) try: try: gc_was_enabled = gc.isenabled() # Disable gc to avoid bug where gc -> file_dealloc -> # write to stderr -> hang. http://bugs.python.org/issue1336 gc.disable() try: self.pid = fork_and_watch(self._on_child, self._loop, True, fork) except: if gc_was_enabled: gc.enable() raise if self.pid == 0: # Child # In various places on the child side of things, we catch OSError # and add attributes to it that detail where in the process we failed; # like all exceptions until we have exec'd, this exception is pickled # and sent to the parent to raise in the calling process. # The parent uses this to decide how to treat that exception, # adjusting certain information about it as needed. # # Python 3.11.8 --- yes, a minor patch release --- stopped # letting the 'filename' parameter get set in the resulting # exception for many cases. We're not quite interpreting this # the same way the stdlib is, I'm sure, but this makes the stdlib # tests pass. # XXX: Technically we're doing a lot of stuff here that # may not be safe to do before a exec(), depending on the OS. # CPython 3 goes to great lengths to precompute a lot # of this info before the fork and pass it all to C functions that # try hard not to call things like malloc(). (Of course, # CPython 2 pretty much did what we're doing.) try: # Close parent's pipe ends if p2cwrite != -1: os.close(p2cwrite) if c2pread != -1: os.close(c2pread) if errread != -1: os.close(errread) os.close(errpipe_read) # When duping fds, if there arises a situation # where one of the fds is either 0, 1 or 2, it # is possible that it is overwritten (#12607). if c2pwrite == 0: c2pwrite = os.dup(c2pwrite) _set_inheritable(c2pwrite, False) while errwrite in (0, 1): errwrite = os.dup(errwrite) _set_inheritable(errwrite, False) # Dup fds for child def _dup2(existing, desired): # dup2() removes the CLOEXEC flag but # we must do it ourselves if dup2() # would be a no-op (issue #10806). if existing == desired: self._set_cloexec_flag(existing, False) elif existing != -1: os.dup2(existing, desired) try: self._remove_nonblock_flag(desired) except OSError: # Ignore EBADF, it may not actually be # open yet. # Tested beginning in 3.7.0b3 test_subprocess.py pass _dup2(p2cread, 0) _dup2(c2pwrite, 1) _dup2(errwrite, 2) # Close pipe fds. Make sure we don't close the # same fd more than once, or standard fds. if not True: closed = set([None]) for fd in (p2cread, c2pwrite, errwrite): if fd not in closed and fd > 2: os.close(fd) closed.add(fd) # Python 3 (with a working set_inheritable): # We no longer manually close p2cread, # c2pwrite, and errwrite here as # _close_open_fds takes care when it is # not already non-inheritable. if cwd is not None: try: os.chdir(cwd) except OSError as e: e._failed_chdir = True raise # Python 3.9 if umask >= 0: os.umask(umask) # XXX: CPython does _Py_RestoreSignals here. # Then setsid() based on ??? try: if gids: os.setgroups(gids) if gid: os.setregid(gid, gid) if uid: os.setreuid(uid, uid) if process_group is not None: os.setpgid(0, process_group) except OSError as e: e._failed_chuser = True raise if preexec_fn: preexec_fn() # Close all other fds, if asked for. This must be done # after preexec_fn runs. if close_fds: fds_to_keep = set(pass_fds) fds_to_keep.add(errpipe_write) self._close_fds(fds_to_keep, errpipe_write) if restore_signals: # restore the documented signals back to sig_dfl; # not all will be defined on every platform for sig in 'SIGPIPE', 'SIGXFZ', 'SIGXFSZ': sig = getattr(signal, sig, None) if sig is not None: signal.signal(sig, signal.SIG_DFL) if start_new_session: os.setsid() try: if env is None: os.execvp(executable, args) else: # Python 3.6 started testing for # bytes values in the env; it also # started encoding strs using # fsencode and using a lower-level # API that takes a list of keys # and values. We don't have access # to that API, so we go the reverse direction. env = {os.fsdecode(k) if isinstance(k, bytes) else k: os.fsdecode(v) if isinstance(v, bytes) else v for k, v in env.items()} os.execvpe(executable, args, env) except OSError as e: e._failed_exec = True raise except: exc_type, exc_value, tb = sys.exc_info() # Save the traceback and attach it to the exception object exc_lines = traceback.format_exception(exc_type, exc_value, tb) exc_value.child_traceback = ''.join(exc_lines) os.write(errpipe_write, pickle.dumps(exc_value)) finally: # Make sure that the process exits no matter what. # The return code does not matter much as it won't be # reported to the application os._exit(1) # Parent self._child_created = True if gc_was_enabled: gc.enable() finally: # be sure the FD is closed no matter what os.close(errpipe_write) # self._devnull is not always defined. devnull_fd = getattr(self, '_devnull', None) if p2cread != -1 and p2cwrite != -1 and p2cread != devnull_fd: os.close(p2cread) if c2pwrite != -1 and c2pread != -1 and c2pwrite != devnull_fd: os.close(c2pwrite) if errwrite != -1 and errread != -1 and errwrite != devnull_fd: os.close(errwrite) if devnull_fd is not None: os.close(devnull_fd) # Prevent a double close of these fds from __init__ on error. self._closed_child_pipe_fds = True # Wait for exec to fail or succeed; possibly raising exception errpipe_read = FileObject(errpipe_read, 'rb') data = errpipe_read.read() finally: try: if hasattr(errpipe_read, 'close'): errpipe_read.close() else: os.close(errpipe_read) except OSError: # Especially on PyPy, we sometimes see the above # `os.close(errpipe_read)` raise an OSError. # It's not entirely clear why, but it happens in # InterprocessSignalTests.test_main sometimes, which must mean # we have some sort of race condition. pass finally: errpipe_read = -1 if data != b"": self.wait() child_exception = pickle.loads(data) for fd in (p2cwrite, c2pread, errread): if fd is not None and fd != -1: os.close(fd) if isinstance(child_exception, OSError): child_exception.filename = executable if hasattr(child_exception, '_failed_chdir'): child_exception.filename = cwd if getattr(child_exception, '_failed_chuser', False): child_exception.filename = None > raise child_exception E OSError: [Errno 8] Exec format error: 'locust' /usr/lib/python3/dist-packages/gevent/subprocess.py:1838: OSError ___ StandaloneIntegrationTests.test_run_autostart_with_multiple_locustfiles ____ self = @unittest.skipIf(os.name == "nt", reason="Signal handling on windows is hard") def test_run_autostart_with_multiple_locustfiles(self): with TemporaryDirectory() as temp_dir: with mock_locustfile(dir=temp_dir): with temporary_file( content=textwrap.dedent( """ from locust import User, task, constant, events class TestUser(User): wait_time = constant(1) @task def my_task(self): print("running my_task()") """ ), dir=temp_dir, ): > proc = subprocess.Popen( [ "locust", "-f", temp_dir, "--autostart", "-u", "2", "--exit-code-on-error", "0", ], stdout=PIPE, stderr=PIPE, text=True, ) locust/test/test_main.py:685: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3/dist-packages/gevent/subprocess.py:808: in __init__ self._execute_child(args, executable, preexec_fn, close_fds, _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = args = ['locust', '-f', '/tmp/tmp_ax0zmd4', '--autostart', '-u', '2', ...] executable = 'locust', preexec_fn = None, close_fds = True, pass_fds = () cwd = None, env = None, universal_newlines = None, startupinfo = None creationflags = 0, shell = False, p2cread = -1, p2cwrite = -1, c2pread = 11 c2pwrite = 81, errread = 82, errwrite = 83, restore_signals = True, gid = None gids = None, uid = None, umask = -1, start_new_session = False process_group = None def _execute_child(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, universal_newlines, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, restore_signals, gid, gids, uid, umask, start_new_session, process_group): """Execute program (POSIX version)""" if isinstance(args, (str, bytes)): args = [args] elif isinstance(args, PathLike): if shell: raise TypeError('path-like args is not allowed when ' 'shell is true') args = [fsencode(args)] # os.PathLike -> [str] else: args = list(args) if shell: # On Android the default shell is at '/system/bin/sh'. unix_shell = ( '/system/bin/sh' if hasattr(sys, 'getandroidapilevel') else '/bin/sh' ) args = [unix_shell, "-c"] + args if executable: args[0] = executable if executable is None: executable = args[0] self._loop.install_sigchld() # For transferring possible exec failure from child to parent # The first char specifies the exception type: 0 means # OSError, 1 means some other error. errpipe_read, errpipe_write = self.pipe_cloexec() # errpipe_write must not be in the standard io 0, 1, or 2 fd range. low_fds_to_close = [] while errpipe_write < 3: low_fds_to_close.append(errpipe_write) errpipe_write = os.dup(errpipe_write) for low_fd in low_fds_to_close: os.close(low_fd) try: try: gc_was_enabled = gc.isenabled() # Disable gc to avoid bug where gc -> file_dealloc -> # write to stderr -> hang. http://bugs.python.org/issue1336 gc.disable() try: self.pid = fork_and_watch(self._on_child, self._loop, True, fork) except: if gc_was_enabled: gc.enable() raise if self.pid == 0: # Child # In various places on the child side of things, we catch OSError # and add attributes to it that detail where in the process we failed; # like all exceptions until we have exec'd, this exception is pickled # and sent to the parent to raise in the calling process. # The parent uses this to decide how to treat that exception, # adjusting certain information about it as needed. # # Python 3.11.8 --- yes, a minor patch release --- stopped # letting the 'filename' parameter get set in the resulting # exception for many cases. We're not quite interpreting this # the same way the stdlib is, I'm sure, but this makes the stdlib # tests pass. # XXX: Technically we're doing a lot of stuff here that # may not be safe to do before a exec(), depending on the OS. # CPython 3 goes to great lengths to precompute a lot # of this info before the fork and pass it all to C functions that # try hard not to call things like malloc(). (Of course, # CPython 2 pretty much did what we're doing.) try: # Close parent's pipe ends if p2cwrite != -1: os.close(p2cwrite) if c2pread != -1: os.close(c2pread) if errread != -1: os.close(errread) os.close(errpipe_read) # When duping fds, if there arises a situation # where one of the fds is either 0, 1 or 2, it # is possible that it is overwritten (#12607). if c2pwrite == 0: c2pwrite = os.dup(c2pwrite) _set_inheritable(c2pwrite, False) while errwrite in (0, 1): errwrite = os.dup(errwrite) _set_inheritable(errwrite, False) # Dup fds for child def _dup2(existing, desired): # dup2() removes the CLOEXEC flag but # we must do it ourselves if dup2() # would be a no-op (issue #10806). if existing == desired: self._set_cloexec_flag(existing, False) elif existing != -1: os.dup2(existing, desired) try: self._remove_nonblock_flag(desired) except OSError: # Ignore EBADF, it may not actually be # open yet. # Tested beginning in 3.7.0b3 test_subprocess.py pass _dup2(p2cread, 0) _dup2(c2pwrite, 1) _dup2(errwrite, 2) # Close pipe fds. Make sure we don't close the # same fd more than once, or standard fds. if not True: closed = set([None]) for fd in (p2cread, c2pwrite, errwrite): if fd not in closed and fd > 2: os.close(fd) closed.add(fd) # Python 3 (with a working set_inheritable): # We no longer manually close p2cread, # c2pwrite, and errwrite here as # _close_open_fds takes care when it is # not already non-inheritable. if cwd is not None: try: os.chdir(cwd) except OSError as e: e._failed_chdir = True raise # Python 3.9 if umask >= 0: os.umask(umask) # XXX: CPython does _Py_RestoreSignals here. # Then setsid() based on ??? try: if gids: os.setgroups(gids) if gid: os.setregid(gid, gid) if uid: os.setreuid(uid, uid) if process_group is not None: os.setpgid(0, process_group) except OSError as e: e._failed_chuser = True raise if preexec_fn: preexec_fn() # Close all other fds, if asked for. This must be done # after preexec_fn runs. if close_fds: fds_to_keep = set(pass_fds) fds_to_keep.add(errpipe_write) self._close_fds(fds_to_keep, errpipe_write) if restore_signals: # restore the documented signals back to sig_dfl; # not all will be defined on every platform for sig in 'SIGPIPE', 'SIGXFZ', 'SIGXFSZ': sig = getattr(signal, sig, None) if sig is not None: signal.signal(sig, signal.SIG_DFL) if start_new_session: os.setsid() try: if env is None: os.execvp(executable, args) else: # Python 3.6 started testing for # bytes values in the env; it also # started encoding strs using # fsencode and using a lower-level # API that takes a list of keys # and values. We don't have access # to that API, so we go the reverse direction. env = {os.fsdecode(k) if isinstance(k, bytes) else k: os.fsdecode(v) if isinstance(v, bytes) else v for k, v in env.items()} os.execvpe(executable, args, env) except OSError as e: e._failed_exec = True raise except: exc_type, exc_value, tb = sys.exc_info() # Save the traceback and attach it to the exception object exc_lines = traceback.format_exception(exc_type, exc_value, tb) exc_value.child_traceback = ''.join(exc_lines) os.write(errpipe_write, pickle.dumps(exc_value)) finally: # Make sure that the process exits no matter what. # The return code does not matter much as it won't be # reported to the application os._exit(1) # Parent self._child_created = True if gc_was_enabled: gc.enable() finally: # be sure the FD is closed no matter what os.close(errpipe_write) # self._devnull is not always defined. devnull_fd = getattr(self, '_devnull', None) if p2cread != -1 and p2cwrite != -1 and p2cread != devnull_fd: os.close(p2cread) if c2pwrite != -1 and c2pread != -1 and c2pwrite != devnull_fd: os.close(c2pwrite) if errwrite != -1 and errread != -1 and errwrite != devnull_fd: os.close(errwrite) if devnull_fd is not None: os.close(devnull_fd) # Prevent a double close of these fds from __init__ on error. self._closed_child_pipe_fds = True # Wait for exec to fail or succeed; possibly raising exception errpipe_read = FileObject(errpipe_read, 'rb') data = errpipe_read.read() finally: try: if hasattr(errpipe_read, 'close'): errpipe_read.close() else: os.close(errpipe_read) except OSError: # Especially on PyPy, we sometimes see the above # `os.close(errpipe_read)` raise an OSError. # It's not entirely clear why, but it happens in # InterprocessSignalTests.test_main sometimes, which must mean # we have some sort of race condition. pass finally: errpipe_read = -1 if data != b"": self.wait() child_exception = pickle.loads(data) for fd in (p2cwrite, c2pread, errread): if fd is not None and fd != -1: os.close(fd) if isinstance(child_exception, OSError): child_exception.filename = executable if hasattr(child_exception, '_failed_chdir'): child_exception.filename = cwd if getattr(child_exception, '_failed_chuser', False): child_exception.filename = None > raise child_exception E OSError: [Errno 8] Exec format error: 'locust' /usr/lib/python3/dist-packages/gevent/subprocess.py:1838: OSError ____ StandaloneIntegrationTests.test_run_headless_with_multiple_locustfiles ____ self = @unittest.skipIf(os.name == "nt", reason="Signal handling on windows is hard") def test_run_headless_with_multiple_locustfiles(self): with TemporaryDirectory() as temp_dir: with mock_locustfile(dir=temp_dir): with temporary_file( content=textwrap.dedent( """ from locust import User, task, constant, events class TestUser(User): wait_time = constant(1) @task def my_task(self): print("running my_task()") """ ), dir=temp_dir, ): > proc = subprocess.Popen( [ "locust", "-f", temp_dir, "--headless", "-u", "2", "--exit-code-on-error", "0", ], stdout=PIPE, stderr=PIPE, text=True, ) locust/test/test_main.py:461: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3/dist-packages/gevent/subprocess.py:808: in __init__ self._execute_child(args, executable, preexec_fn, close_fds, _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = args = ['locust', '-f', '/tmp/tmpgq6gl459', '--headless', '-u', '2', ...] executable = 'locust', preexec_fn = None, close_fds = True, pass_fds = () cwd = None, env = None, universal_newlines = None, startupinfo = None creationflags = 0, shell = False, p2cread = -1, p2cwrite = -1, c2pread = 11 c2pwrite = 81, errread = 82, errwrite = 83, restore_signals = True, gid = None gids = None, uid = None, umask = -1, start_new_session = False process_group = None def _execute_child(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, universal_newlines, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, restore_signals, gid, gids, uid, umask, start_new_session, process_group): """Execute program (POSIX version)""" if isinstance(args, (str, bytes)): args = [args] elif isinstance(args, PathLike): if shell: raise TypeError('path-like args is not allowed when ' 'shell is true') args = [fsencode(args)] # os.PathLike -> [str] else: args = list(args) if shell: # On Android the default shell is at '/system/bin/sh'. unix_shell = ( '/system/bin/sh' if hasattr(sys, 'getandroidapilevel') else '/bin/sh' ) args = [unix_shell, "-c"] + args if executable: args[0] = executable if executable is None: executable = args[0] self._loop.install_sigchld() # For transferring possible exec failure from child to parent # The first char specifies the exception type: 0 means # OSError, 1 means some other error. errpipe_read, errpipe_write = self.pipe_cloexec() # errpipe_write must not be in the standard io 0, 1, or 2 fd range. low_fds_to_close = [] while errpipe_write < 3: low_fds_to_close.append(errpipe_write) errpipe_write = os.dup(errpipe_write) for low_fd in low_fds_to_close: os.close(low_fd) try: try: gc_was_enabled = gc.isenabled() # Disable gc to avoid bug where gc -> file_dealloc -> # write to stderr -> hang. http://bugs.python.org/issue1336 gc.disable() try: self.pid = fork_and_watch(self._on_child, self._loop, True, fork) except: if gc_was_enabled: gc.enable() raise if self.pid == 0: # Child # In various places on the child side of things, we catch OSError # and add attributes to it that detail where in the process we failed; # like all exceptions until we have exec'd, this exception is pickled # and sent to the parent to raise in the calling process. # The parent uses this to decide how to treat that exception, # adjusting certain information about it as needed. # # Python 3.11.8 --- yes, a minor patch release --- stopped # letting the 'filename' parameter get set in the resulting # exception for many cases. We're not quite interpreting this # the same way the stdlib is, I'm sure, but this makes the stdlib # tests pass. # XXX: Technically we're doing a lot of stuff here that # may not be safe to do before a exec(), depending on the OS. # CPython 3 goes to great lengths to precompute a lot # of this info before the fork and pass it all to C functions that # try hard not to call things like malloc(). (Of course, # CPython 2 pretty much did what we're doing.) try: # Close parent's pipe ends if p2cwrite != -1: os.close(p2cwrite) if c2pread != -1: os.close(c2pread) if errread != -1: os.close(errread) os.close(errpipe_read) # When duping fds, if there arises a situation # where one of the fds is either 0, 1 or 2, it # is possible that it is overwritten (#12607). if c2pwrite == 0: c2pwrite = os.dup(c2pwrite) _set_inheritable(c2pwrite, False) while errwrite in (0, 1): errwrite = os.dup(errwrite) _set_inheritable(errwrite, False) # Dup fds for child def _dup2(existing, desired): # dup2() removes the CLOEXEC flag but # we must do it ourselves if dup2() # would be a no-op (issue #10806). if existing == desired: self._set_cloexec_flag(existing, False) elif existing != -1: os.dup2(existing, desired) try: self._remove_nonblock_flag(desired) except OSError: # Ignore EBADF, it may not actually be # open yet. # Tested beginning in 3.7.0b3 test_subprocess.py pass _dup2(p2cread, 0) _dup2(c2pwrite, 1) _dup2(errwrite, 2) # Close pipe fds. Make sure we don't close the # same fd more than once, or standard fds. if not True: closed = set([None]) for fd in (p2cread, c2pwrite, errwrite): if fd not in closed and fd > 2: os.close(fd) closed.add(fd) # Python 3 (with a working set_inheritable): # We no longer manually close p2cread, # c2pwrite, and errwrite here as # _close_open_fds takes care when it is # not already non-inheritable. if cwd is not None: try: os.chdir(cwd) except OSError as e: e._failed_chdir = True raise # Python 3.9 if umask >= 0: os.umask(umask) # XXX: CPython does _Py_RestoreSignals here. # Then setsid() based on ??? try: if gids: os.setgroups(gids) if gid: os.setregid(gid, gid) if uid: os.setreuid(uid, uid) if process_group is not None: os.setpgid(0, process_group) except OSError as e: e._failed_chuser = True raise if preexec_fn: preexec_fn() # Close all other fds, if asked for. This must be done # after preexec_fn runs. if close_fds: fds_to_keep = set(pass_fds) fds_to_keep.add(errpipe_write) self._close_fds(fds_to_keep, errpipe_write) if restore_signals: # restore the documented signals back to sig_dfl; # not all will be defined on every platform for sig in 'SIGPIPE', 'SIGXFZ', 'SIGXFSZ': sig = getattr(signal, sig, None) if sig is not None: signal.signal(sig, signal.SIG_DFL) if start_new_session: os.setsid() try: if env is None: os.execvp(executable, args) else: # Python 3.6 started testing for # bytes values in the env; it also # started encoding strs using # fsencode and using a lower-level # API that takes a list of keys # and values. We don't have access # to that API, so we go the reverse direction. env = {os.fsdecode(k) if isinstance(k, bytes) else k: os.fsdecode(v) if isinstance(v, bytes) else v for k, v in env.items()} os.execvpe(executable, args, env) except OSError as e: e._failed_exec = True raise except: exc_type, exc_value, tb = sys.exc_info() # Save the traceback and attach it to the exception object exc_lines = traceback.format_exception(exc_type, exc_value, tb) exc_value.child_traceback = ''.join(exc_lines) os.write(errpipe_write, pickle.dumps(exc_value)) finally: # Make sure that the process exits no matter what. # The return code does not matter much as it won't be # reported to the application os._exit(1) # Parent self._child_created = True if gc_was_enabled: gc.enable() finally: # be sure the FD is closed no matter what os.close(errpipe_write) # self._devnull is not always defined. devnull_fd = getattr(self, '_devnull', None) if p2cread != -1 and p2cwrite != -1 and p2cread != devnull_fd: os.close(p2cread) if c2pwrite != -1 and c2pread != -1 and c2pwrite != devnull_fd: os.close(c2pwrite) if errwrite != -1 and errread != -1 and errwrite != devnull_fd: os.close(errwrite) if devnull_fd is not None: os.close(devnull_fd) # Prevent a double close of these fds from __init__ on error. self._closed_child_pipe_fds = True # Wait for exec to fail or succeed; possibly raising exception errpipe_read = FileObject(errpipe_read, 'rb') data = errpipe_read.read() finally: try: if hasattr(errpipe_read, 'close'): errpipe_read.close() else: os.close(errpipe_read) except OSError: # Especially on PyPy, we sometimes see the above # `os.close(errpipe_read)` raise an OSError. # It's not entirely clear why, but it happens in # InterprocessSignalTests.test_main sometimes, which must mean # we have some sort of race condition. pass finally: errpipe_read = -1 if data != b"": self.wait() child_exception = pickle.loads(data) for fd in (p2cwrite, c2pread, errread): if fd is not None and fd != -1: os.close(fd) if isinstance(child_exception, OSError): child_exception.filename = executable if hasattr(child_exception, '_failed_chdir'): child_exception.filename = cwd if getattr(child_exception, '_failed_chuser', False): child_exception.filename = None > raise child_exception E OSError: [Errno 8] Exec format error: 'locust' /usr/lib/python3/dist-packages/gevent/subprocess.py:1838: OSError _ StandaloneIntegrationTests.test_run_headless_with_multiple_locustfiles_with_shape _ self = def test_run_headless_with_multiple_locustfiles_with_shape(self): content = textwrap.dedent( """ from locust import User, task, between class TestUser2(User): wait_time = between(2, 4) @task def my_task(self): print("running my_task() again") """ ) with mock_locustfile(content=content) as mocked1: with temporary_file( content=textwrap.dedent( """ from locust import User, task, between, LoadTestShape class LoadTestShape(LoadTestShape): def tick(self): run_time = self.get_run_time() if run_time < 2: return (10, 1) return None class TestUser(User): wait_time = between(2, 4) @task def my_task(self): print("running my_task()") """ ) ) as mocked2: > proc = subprocess.Popen( [ "locust", "-f", f"{mocked1.file_path},{mocked2}", "--host", "https://test.com/", "--headless", "--exit-code-on-error", "0", ], stdout=PIPE, stderr=PIPE, text=True, ) locust/test/test_main.py:565: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3/dist-packages/gevent/subprocess.py:808: in __init__ self._execute_child(args, executable, preexec_fn, close_fds, _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = args = ['locust', '-f', '/build/reproducible-path/locust-2.24.0/locust/test/mock_locustfile_1715255809_630645_64013.py,/tmp/tmpvqaayteo_locustfile.py', '--host', 'https://test.com/', '--headless', ...] executable = 'locust', preexec_fn = None, close_fds = True, pass_fds = () cwd = None, env = None, universal_newlines = None, startupinfo = None creationflags = 0, shell = False, p2cread = -1, p2cwrite = -1, c2pread = 11 c2pwrite = 81, errread = 82, errwrite = 83, restore_signals = True, gid = None gids = None, uid = None, umask = -1, start_new_session = False process_group = None def _execute_child(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, universal_newlines, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, restore_signals, gid, gids, uid, umask, start_new_session, process_group): """Execute program (POSIX version)""" if isinstance(args, (str, bytes)): args = [args] elif isinstance(args, PathLike): if shell: raise TypeError('path-like args is not allowed when ' 'shell is true') args = [fsencode(args)] # os.PathLike -> [str] else: args = list(args) if shell: # On Android the default shell is at '/system/bin/sh'. unix_shell = ( '/system/bin/sh' if hasattr(sys, 'getandroidapilevel') else '/bin/sh' ) args = [unix_shell, "-c"] + args if executable: args[0] = executable if executable is None: executable = args[0] self._loop.install_sigchld() # For transferring possible exec failure from child to parent # The first char specifies the exception type: 0 means # OSError, 1 means some other error. errpipe_read, errpipe_write = self.pipe_cloexec() # errpipe_write must not be in the standard io 0, 1, or 2 fd range. low_fds_to_close = [] while errpipe_write < 3: low_fds_to_close.append(errpipe_write) errpipe_write = os.dup(errpipe_write) for low_fd in low_fds_to_close: os.close(low_fd) try: try: gc_was_enabled = gc.isenabled() # Disable gc to avoid bug where gc -> file_dealloc -> # write to stderr -> hang. http://bugs.python.org/issue1336 gc.disable() try: self.pid = fork_and_watch(self._on_child, self._loop, True, fork) except: if gc_was_enabled: gc.enable() raise if self.pid == 0: # Child # In various places on the child side of things, we catch OSError # and add attributes to it that detail where in the process we failed; # like all exceptions until we have exec'd, this exception is pickled # and sent to the parent to raise in the calling process. # The parent uses this to decide how to treat that exception, # adjusting certain information about it as needed. # # Python 3.11.8 --- yes, a minor patch release --- stopped # letting the 'filename' parameter get set in the resulting # exception for many cases. We're not quite interpreting this # the same way the stdlib is, I'm sure, but this makes the stdlib # tests pass. # XXX: Technically we're doing a lot of stuff here that # may not be safe to do before a exec(), depending on the OS. # CPython 3 goes to great lengths to precompute a lot # of this info before the fork and pass it all to C functions that # try hard not to call things like malloc(). (Of course, # CPython 2 pretty much did what we're doing.) try: # Close parent's pipe ends if p2cwrite != -1: os.close(p2cwrite) if c2pread != -1: os.close(c2pread) if errread != -1: os.close(errread) os.close(errpipe_read) # When duping fds, if there arises a situation # where one of the fds is either 0, 1 or 2, it # is possible that it is overwritten (#12607). if c2pwrite == 0: c2pwrite = os.dup(c2pwrite) _set_inheritable(c2pwrite, False) while errwrite in (0, 1): errwrite = os.dup(errwrite) _set_inheritable(errwrite, False) # Dup fds for child def _dup2(existing, desired): # dup2() removes the CLOEXEC flag but # we must do it ourselves if dup2() # would be a no-op (issue #10806). if existing == desired: self._set_cloexec_flag(existing, False) elif existing != -1: os.dup2(existing, desired) try: self._remove_nonblock_flag(desired) except OSError: # Ignore EBADF, it may not actually be # open yet. # Tested beginning in 3.7.0b3 test_subprocess.py pass _dup2(p2cread, 0) _dup2(c2pwrite, 1) _dup2(errwrite, 2) # Close pipe fds. Make sure we don't close the # same fd more than once, or standard fds. if not True: closed = set([None]) for fd in (p2cread, c2pwrite, errwrite): if fd not in closed and fd > 2: os.close(fd) closed.add(fd) # Python 3 (with a working set_inheritable): # We no longer manually close p2cread, # c2pwrite, and errwrite here as # _close_open_fds takes care when it is # not already non-inheritable. if cwd is not None: try: os.chdir(cwd) except OSError as e: e._failed_chdir = True raise # Python 3.9 if umask >= 0: os.umask(umask) # XXX: CPython does _Py_RestoreSignals here. # Then setsid() based on ??? try: if gids: os.setgroups(gids) if gid: os.setregid(gid, gid) if uid: os.setreuid(uid, uid) if process_group is not None: os.setpgid(0, process_group) except OSError as e: e._failed_chuser = True raise if preexec_fn: preexec_fn() # Close all other fds, if asked for. This must be done # after preexec_fn runs. if close_fds: fds_to_keep = set(pass_fds) fds_to_keep.add(errpipe_write) self._close_fds(fds_to_keep, errpipe_write) if restore_signals: # restore the documented signals back to sig_dfl; # not all will be defined on every platform for sig in 'SIGPIPE', 'SIGXFZ', 'SIGXFSZ': sig = getattr(signal, sig, None) if sig is not None: signal.signal(sig, signal.SIG_DFL) if start_new_session: os.setsid() try: if env is None: os.execvp(executable, args) else: # Python 3.6 started testing for # bytes values in the env; it also # started encoding strs using # fsencode and using a lower-level # API that takes a list of keys # and values. We don't have access # to that API, so we go the reverse direction. env = {os.fsdecode(k) if isinstance(k, bytes) else k: os.fsdecode(v) if isinstance(v, bytes) else v for k, v in env.items()} os.execvpe(executable, args, env) except OSError as e: e._failed_exec = True raise except: exc_type, exc_value, tb = sys.exc_info() # Save the traceback and attach it to the exception object exc_lines = traceback.format_exception(exc_type, exc_value, tb) exc_value.child_traceback = ''.join(exc_lines) os.write(errpipe_write, pickle.dumps(exc_value)) finally: # Make sure that the process exits no matter what. # The return code does not matter much as it won't be # reported to the application os._exit(1) # Parent self._child_created = True if gc_was_enabled: gc.enable() finally: # be sure the FD is closed no matter what os.close(errpipe_write) # self._devnull is not always defined. devnull_fd = getattr(self, '_devnull', None) if p2cread != -1 and p2cwrite != -1 and p2cread != devnull_fd: os.close(p2cread) if c2pwrite != -1 and c2pread != -1 and c2pwrite != devnull_fd: os.close(c2pwrite) if errwrite != -1 and errread != -1 and errwrite != devnull_fd: os.close(errwrite) if devnull_fd is not None: os.close(devnull_fd) # Prevent a double close of these fds from __init__ on error. self._closed_child_pipe_fds = True # Wait for exec to fail or succeed; possibly raising exception errpipe_read = FileObject(errpipe_read, 'rb') data = errpipe_read.read() finally: try: if hasattr(errpipe_read, 'close'): errpipe_read.close() else: os.close(errpipe_read) except OSError: # Especially on PyPy, we sometimes see the above # `os.close(errpipe_read)` raise an OSError. # It's not entirely clear why, but it happens in # InterprocessSignalTests.test_main sometimes, which must mean # we have some sort of race condition. pass finally: errpipe_read = -1 if data != b"": self.wait() child_exception = pickle.loads(data) for fd in (p2cwrite, c2pread, errread): if fd is not None and fd != -1: os.close(fd) if isinstance(child_exception, OSError): child_exception.filename = executable if hasattr(child_exception, '_failed_chdir'): child_exception.filename = cwd if getattr(child_exception, '_failed_chuser', False): child_exception.filename = None > raise child_exception E OSError: [Errno 8] Exec format error: 'locust' /usr/lib/python3/dist-packages/gevent/subprocess.py:1838: OSError __________ StandaloneIntegrationTests.test_run_with_userclass_picker ___________ self = def test_run_with_userclass_picker(self): with temporary_file(content=MOCK_LOCUSTFILE_CONTENT_A) as file1: with temporary_file(content=MOCK_LOCUSTFILE_CONTENT_B) as file2: > proc = subprocess.Popen( ["locust", "-f", f"{file1},{file2}", "--class-picker"], stdout=PIPE, stderr=PIPE, text=True, ) locust/test/test_main.py:1130: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3/dist-packages/gevent/subprocess.py:808: in __init__ self._execute_child(args, executable, preexec_fn, close_fds, _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = args = ['locust', '-f', '/tmp/tmpmrr5gj_8_locustfile.py,/tmp/tmprrkmtrwj_locustfile.py', '--class-picker'] executable = 'locust', preexec_fn = None, close_fds = True, pass_fds = () cwd = None, env = None, universal_newlines = None, startupinfo = None creationflags = 0, shell = False, p2cread = -1, p2cwrite = -1, c2pread = 11 c2pwrite = 81, errread = 82, errwrite = 83, restore_signals = True, gid = None gids = None, uid = None, umask = -1, start_new_session = False process_group = None def _execute_child(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, universal_newlines, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, restore_signals, gid, gids, uid, umask, start_new_session, process_group): """Execute program (POSIX version)""" if isinstance(args, (str, bytes)): args = [args] elif isinstance(args, PathLike): if shell: raise TypeError('path-like args is not allowed when ' 'shell is true') args = [fsencode(args)] # os.PathLike -> [str] else: args = list(args) if shell: # On Android the default shell is at '/system/bin/sh'. unix_shell = ( '/system/bin/sh' if hasattr(sys, 'getandroidapilevel') else '/bin/sh' ) args = [unix_shell, "-c"] + args if executable: args[0] = executable if executable is None: executable = args[0] self._loop.install_sigchld() # For transferring possible exec failure from child to parent # The first char specifies the exception type: 0 means # OSError, 1 means some other error. errpipe_read, errpipe_write = self.pipe_cloexec() # errpipe_write must not be in the standard io 0, 1, or 2 fd range. low_fds_to_close = [] while errpipe_write < 3: low_fds_to_close.append(errpipe_write) errpipe_write = os.dup(errpipe_write) for low_fd in low_fds_to_close: os.close(low_fd) try: try: gc_was_enabled = gc.isenabled() # Disable gc to avoid bug where gc -> file_dealloc -> # write to stderr -> hang. http://bugs.python.org/issue1336 gc.disable() try: self.pid = fork_and_watch(self._on_child, self._loop, True, fork) except: if gc_was_enabled: gc.enable() raise if self.pid == 0: # Child # In various places on the child side of things, we catch OSError # and add attributes to it that detail where in the process we failed; # like all exceptions until we have exec'd, this exception is pickled # and sent to the parent to raise in the calling process. # The parent uses this to decide how to treat that exception, # adjusting certain information about it as needed. # # Python 3.11.8 --- yes, a minor patch release --- stopped # letting the 'filename' parameter get set in the resulting # exception for many cases. We're not quite interpreting this # the same way the stdlib is, I'm sure, but this makes the stdlib # tests pass. # XXX: Technically we're doing a lot of stuff here that # may not be safe to do before a exec(), depending on the OS. # CPython 3 goes to great lengths to precompute a lot # of this info before the fork and pass it all to C functions that # try hard not to call things like malloc(). (Of course, # CPython 2 pretty much did what we're doing.) try: # Close parent's pipe ends if p2cwrite != -1: os.close(p2cwrite) if c2pread != -1: os.close(c2pread) if errread != -1: os.close(errread) os.close(errpipe_read) # When duping fds, if there arises a situation # where one of the fds is either 0, 1 or 2, it # is possible that it is overwritten (#12607). if c2pwrite == 0: c2pwrite = os.dup(c2pwrite) _set_inheritable(c2pwrite, False) while errwrite in (0, 1): errwrite = os.dup(errwrite) _set_inheritable(errwrite, False) # Dup fds for child def _dup2(existing, desired): # dup2() removes the CLOEXEC flag but # we must do it ourselves if dup2() # would be a no-op (issue #10806). if existing == desired: self._set_cloexec_flag(existing, False) elif existing != -1: os.dup2(existing, desired) try: self._remove_nonblock_flag(desired) except OSError: # Ignore EBADF, it may not actually be # open yet. # Tested beginning in 3.7.0b3 test_subprocess.py pass _dup2(p2cread, 0) _dup2(c2pwrite, 1) _dup2(errwrite, 2) # Close pipe fds. Make sure we don't close the # same fd more than once, or standard fds. if not True: closed = set([None]) for fd in (p2cread, c2pwrite, errwrite): if fd not in closed and fd > 2: os.close(fd) closed.add(fd) # Python 3 (with a working set_inheritable): # We no longer manually close p2cread, # c2pwrite, and errwrite here as # _close_open_fds takes care when it is # not already non-inheritable. if cwd is not None: try: os.chdir(cwd) except OSError as e: e._failed_chdir = True raise # Python 3.9 if umask >= 0: os.umask(umask) # XXX: CPython does _Py_RestoreSignals here. # Then setsid() based on ??? try: if gids: os.setgroups(gids) if gid: os.setregid(gid, gid) if uid: os.setreuid(uid, uid) if process_group is not None: os.setpgid(0, process_group) except OSError as e: e._failed_chuser = True raise if preexec_fn: preexec_fn() # Close all other fds, if asked for. This must be done # after preexec_fn runs. if close_fds: fds_to_keep = set(pass_fds) fds_to_keep.add(errpipe_write) self._close_fds(fds_to_keep, errpipe_write) if restore_signals: # restore the documented signals back to sig_dfl; # not all will be defined on every platform for sig in 'SIGPIPE', 'SIGXFZ', 'SIGXFSZ': sig = getattr(signal, sig, None) if sig is not None: signal.signal(sig, signal.SIG_DFL) if start_new_session: os.setsid() try: if env is None: os.execvp(executable, args) else: # Python 3.6 started testing for # bytes values in the env; it also # started encoding strs using # fsencode and using a lower-level # API that takes a list of keys # and values. We don't have access # to that API, so we go the reverse direction. env = {os.fsdecode(k) if isinstance(k, bytes) else k: os.fsdecode(v) if isinstance(v, bytes) else v for k, v in env.items()} os.execvpe(executable, args, env) except OSError as e: e._failed_exec = True raise except: exc_type, exc_value, tb = sys.exc_info() # Save the traceback and attach it to the exception object exc_lines = traceback.format_exception(exc_type, exc_value, tb) exc_value.child_traceback = ''.join(exc_lines) os.write(errpipe_write, pickle.dumps(exc_value)) finally: # Make sure that the process exits no matter what. # The return code does not matter much as it won't be # reported to the application os._exit(1) # Parent self._child_created = True if gc_was_enabled: gc.enable() finally: # be sure the FD is closed no matter what os.close(errpipe_write) # self._devnull is not always defined. devnull_fd = getattr(self, '_devnull', None) if p2cread != -1 and p2cwrite != -1 and p2cread != devnull_fd: os.close(p2cread) if c2pwrite != -1 and c2pread != -1 and c2pwrite != devnull_fd: os.close(c2pwrite) if errwrite != -1 and errread != -1 and errwrite != devnull_fd: os.close(errwrite) if devnull_fd is not None: os.close(devnull_fd) # Prevent a double close of these fds from __init__ on error. self._closed_child_pipe_fds = True # Wait for exec to fail or succeed; possibly raising exception errpipe_read = FileObject(errpipe_read, 'rb') data = errpipe_read.read() finally: try: if hasattr(errpipe_read, 'close'): errpipe_read.close() else: os.close(errpipe_read) except OSError: # Especially on PyPy, we sometimes see the above # `os.close(errpipe_read)` raise an OSError. # It's not entirely clear why, but it happens in # InterprocessSignalTests.test_main sometimes, which must mean # we have some sort of race condition. pass finally: errpipe_read = -1 if data != b"": self.wait() child_exception = pickle.loads(data) for fd in (p2cwrite, c2pread, errread): if fd is not None and fd != -1: os.close(fd) if isinstance(child_exception, OSError): child_exception.filename = executable if hasattr(child_exception, '_failed_chdir'): child_exception.filename = cwd if getattr(child_exception, '_failed_chuser', False): child_exception.filename = None > raise child_exception E OSError: [Errno 8] Exec format error: 'locust' /usr/lib/python3/dist-packages/gevent/subprocess.py:1838: OSError _____ StandaloneIntegrationTests.test_shape_class_log_disabled_parameters ______ self = def test_shape_class_log_disabled_parameters(self): content = MOCK_LOCUSTFILE_CONTENT + textwrap.dedent( """ from locust import LoadTestShape class TestShape(LoadTestShape): def tick(self): return None """ ) with mock_locustfile(content=content) as mocked: > out = self.assert_run( [ "locust", "--headless", "-f", mocked.file_path, "--exit-code-on-error=0", "--users=1", "--spawn-rate=1", ] ) locust/test/test_main.py:1252: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ locust/test/test_main.py:65: in assert_run out = subprocess.run(cmd, capture_output=True, text=True, timeout=timeout) /usr/lib/python3/dist-packages/gevent/subprocess.py:2001: in run with Popen(*popenargs, **kwargs) as process: /usr/lib/python3/dist-packages/gevent/subprocess.py:808: in __init__ self._execute_child(args, executable, preexec_fn, close_fds, _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = args = ['locust', '--headless', '-f', '/build/reproducible-path/locust-2.24.0/locust/test/mock_locustfile_1715255810_0204446_99900.py', '--exit-code-on-error=0', '--users=1', ...] executable = 'locust', preexec_fn = None, close_fds = True, pass_fds = () cwd = None, env = None, universal_newlines = None, startupinfo = None creationflags = 0, shell = False, p2cread = -1, p2cwrite = -1, c2pread = 11 c2pwrite = 81, errread = 82, errwrite = 83, restore_signals = True, gid = None gids = None, uid = None, umask = -1, start_new_session = False process_group = None def _execute_child(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, universal_newlines, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, restore_signals, gid, gids, uid, umask, start_new_session, process_group): """Execute program (POSIX version)""" if isinstance(args, (str, bytes)): args = [args] elif isinstance(args, PathLike): if shell: raise TypeError('path-like args is not allowed when ' 'shell is true') args = [fsencode(args)] # os.PathLike -> [str] else: args = list(args) if shell: # On Android the default shell is at '/system/bin/sh'. unix_shell = ( '/system/bin/sh' if hasattr(sys, 'getandroidapilevel') else '/bin/sh' ) args = [unix_shell, "-c"] + args if executable: args[0] = executable if executable is None: executable = args[0] self._loop.install_sigchld() # For transferring possible exec failure from child to parent # The first char specifies the exception type: 0 means # OSError, 1 means some other error. errpipe_read, errpipe_write = self.pipe_cloexec() # errpipe_write must not be in the standard io 0, 1, or 2 fd range. low_fds_to_close = [] while errpipe_write < 3: low_fds_to_close.append(errpipe_write) errpipe_write = os.dup(errpipe_write) for low_fd in low_fds_to_close: os.close(low_fd) try: try: gc_was_enabled = gc.isenabled() # Disable gc to avoid bug where gc -> file_dealloc -> # write to stderr -> hang. http://bugs.python.org/issue1336 gc.disable() try: self.pid = fork_and_watch(self._on_child, self._loop, True, fork) except: if gc_was_enabled: gc.enable() raise if self.pid == 0: # Child # In various places on the child side of things, we catch OSError # and add attributes to it that detail where in the process we failed; # like all exceptions until we have exec'd, this exception is pickled # and sent to the parent to raise in the calling process. # The parent uses this to decide how to treat that exception, # adjusting certain information about it as needed. # # Python 3.11.8 --- yes, a minor patch release --- stopped # letting the 'filename' parameter get set in the resulting # exception for many cases. We're not quite interpreting this # the same way the stdlib is, I'm sure, but this makes the stdlib # tests pass. # XXX: Technically we're doing a lot of stuff here that # may not be safe to do before a exec(), depending on the OS. # CPython 3 goes to great lengths to precompute a lot # of this info before the fork and pass it all to C functions that # try hard not to call things like malloc(). (Of course, # CPython 2 pretty much did what we're doing.) try: # Close parent's pipe ends if p2cwrite != -1: os.close(p2cwrite) if c2pread != -1: os.close(c2pread) if errread != -1: os.close(errread) os.close(errpipe_read) # When duping fds, if there arises a situation # where one of the fds is either 0, 1 or 2, it # is possible that it is overwritten (#12607). if c2pwrite == 0: c2pwrite = os.dup(c2pwrite) _set_inheritable(c2pwrite, False) while errwrite in (0, 1): errwrite = os.dup(errwrite) _set_inheritable(errwrite, False) # Dup fds for child def _dup2(existing, desired): # dup2() removes the CLOEXEC flag but # we must do it ourselves if dup2() # would be a no-op (issue #10806). if existing == desired: self._set_cloexec_flag(existing, False) elif existing != -1: os.dup2(existing, desired) try: self._remove_nonblock_flag(desired) except OSError: # Ignore EBADF, it may not actually be # open yet. # Tested beginning in 3.7.0b3 test_subprocess.py pass _dup2(p2cread, 0) _dup2(c2pwrite, 1) _dup2(errwrite, 2) # Close pipe fds. Make sure we don't close the # same fd more than once, or standard fds. if not True: closed = set([None]) for fd in (p2cread, c2pwrite, errwrite): if fd not in closed and fd > 2: os.close(fd) closed.add(fd) # Python 3 (with a working set_inheritable): # We no longer manually close p2cread, # c2pwrite, and errwrite here as # _close_open_fds takes care when it is # not already non-inheritable. if cwd is not None: try: os.chdir(cwd) except OSError as e: e._failed_chdir = True raise # Python 3.9 if umask >= 0: os.umask(umask) # XXX: CPython does _Py_RestoreSignals here. # Then setsid() based on ??? try: if gids: os.setgroups(gids) if gid: os.setregid(gid, gid) if uid: os.setreuid(uid, uid) if process_group is not None: os.setpgid(0, process_group) except OSError as e: e._failed_chuser = True raise if preexec_fn: preexec_fn() # Close all other fds, if asked for. This must be done # after preexec_fn runs. if close_fds: fds_to_keep = set(pass_fds) fds_to_keep.add(errpipe_write) self._close_fds(fds_to_keep, errpipe_write) if restore_signals: # restore the documented signals back to sig_dfl; # not all will be defined on every platform for sig in 'SIGPIPE', 'SIGXFZ', 'SIGXFSZ': sig = getattr(signal, sig, None) if sig is not None: signal.signal(sig, signal.SIG_DFL) if start_new_session: os.setsid() try: if env is None: os.execvp(executable, args) else: # Python 3.6 started testing for # bytes values in the env; it also # started encoding strs using # fsencode and using a lower-level # API that takes a list of keys # and values. We don't have access # to that API, so we go the reverse direction. env = {os.fsdecode(k) if isinstance(k, bytes) else k: os.fsdecode(v) if isinstance(v, bytes) else v for k, v in env.items()} os.execvpe(executable, args, env) except OSError as e: e._failed_exec = True raise except: exc_type, exc_value, tb = sys.exc_info() # Save the traceback and attach it to the exception object exc_lines = traceback.format_exception(exc_type, exc_value, tb) exc_value.child_traceback = ''.join(exc_lines) os.write(errpipe_write, pickle.dumps(exc_value)) finally: # Make sure that the process exits no matter what. # The return code does not matter much as it won't be # reported to the application os._exit(1) # Parent self._child_created = True if gc_was_enabled: gc.enable() finally: # be sure the FD is closed no matter what os.close(errpipe_write) # self._devnull is not always defined. devnull_fd = getattr(self, '_devnull', None) if p2cread != -1 and p2cwrite != -1 and p2cread != devnull_fd: os.close(p2cread) if c2pwrite != -1 and c2pread != -1 and c2pwrite != devnull_fd: os.close(c2pwrite) if errwrite != -1 and errread != -1 and errwrite != devnull_fd: os.close(errwrite) if devnull_fd is not None: os.close(devnull_fd) # Prevent a double close of these fds from __init__ on error. self._closed_child_pipe_fds = True # Wait for exec to fail or succeed; possibly raising exception errpipe_read = FileObject(errpipe_read, 'rb') data = errpipe_read.read() finally: try: if hasattr(errpipe_read, 'close'): errpipe_read.close() else: os.close(errpipe_read) except OSError: # Especially on PyPy, we sometimes see the above # `os.close(errpipe_read)` raise an OSError. # It's not entirely clear why, but it happens in # InterprocessSignalTests.test_main sometimes, which must mean # we have some sort of race condition. pass finally: errpipe_read = -1 if data != b"": self.wait() child_exception = pickle.loads(data) for fd in (p2cwrite, c2pread, errread): if fd is not None and fd != -1: os.close(fd) if isinstance(child_exception, OSError): child_exception.filename = executable if hasattr(child_exception, '_failed_chdir'): child_exception.filename = cwd if getattr(child_exception, '_failed_chuser', False): child_exception.filename = None > raise child_exception E OSError: [Errno 8] Exec format error: 'locust' /usr/lib/python3/dist-packages/gevent/subprocess.py:1838: OSError _____ StandaloneIntegrationTests.test_shape_class_with_use_common_options ______ self = def test_shape_class_with_use_common_options(self): content = MOCK_LOCUSTFILE_CONTENT + textwrap.dedent( """ from locust import LoadTestShape class TestShape(LoadTestShape): use_common_options = True def tick(self): return None """ ) with mock_locustfile(content=content) as mocked: > out = self.assert_run( [ "locust", "-f", mocked.file_path, "--run-time=1s", "--users=1", "--spawn-rate=1", "--headless", "--exit-code-on-error=0", ] ) locust/test/test_main.py:1280: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ locust/test/test_main.py:65: in assert_run out = subprocess.run(cmd, capture_output=True, text=True, timeout=timeout) /usr/lib/python3/dist-packages/gevent/subprocess.py:2001: in run with Popen(*popenargs, **kwargs) as process: /usr/lib/python3/dist-packages/gevent/subprocess.py:808: in __init__ self._execute_child(args, executable, preexec_fn, close_fds, _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = args = ['locust', '-f', '/build/reproducible-path/locust-2.24.0/locust/test/mock_locustfile_1715255810_274743_34251.py', '--run-time=1s', '--users=1', '--spawn-rate=1', ...] executable = 'locust', preexec_fn = None, close_fds = True, pass_fds = () cwd = None, env = None, universal_newlines = None, startupinfo = None creationflags = 0, shell = False, p2cread = -1, p2cwrite = -1, c2pread = 11 c2pwrite = 81, errread = 82, errwrite = 83, restore_signals = True, gid = None gids = None, uid = None, umask = -1, start_new_session = False process_group = None def _execute_child(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, universal_newlines, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, restore_signals, gid, gids, uid, umask, start_new_session, process_group): """Execute program (POSIX version)""" if isinstance(args, (str, bytes)): args = [args] elif isinstance(args, PathLike): if shell: raise TypeError('path-like args is not allowed when ' 'shell is true') args = [fsencode(args)] # os.PathLike -> [str] else: args = list(args) if shell: # On Android the default shell is at '/system/bin/sh'. unix_shell = ( '/system/bin/sh' if hasattr(sys, 'getandroidapilevel') else '/bin/sh' ) args = [unix_shell, "-c"] + args if executable: args[0] = executable if executable is None: executable = args[0] self._loop.install_sigchld() # For transferring possible exec failure from child to parent # The first char specifies the exception type: 0 means # OSError, 1 means some other error. errpipe_read, errpipe_write = self.pipe_cloexec() # errpipe_write must not be in the standard io 0, 1, or 2 fd range. low_fds_to_close = [] while errpipe_write < 3: low_fds_to_close.append(errpipe_write) errpipe_write = os.dup(errpipe_write) for low_fd in low_fds_to_close: os.close(low_fd) try: try: gc_was_enabled = gc.isenabled() # Disable gc to avoid bug where gc -> file_dealloc -> # write to stderr -> hang. http://bugs.python.org/issue1336 gc.disable() try: self.pid = fork_and_watch(self._on_child, self._loop, True, fork) except: if gc_was_enabled: gc.enable() raise if self.pid == 0: # Child # In various places on the child side of things, we catch OSError # and add attributes to it that detail where in the process we failed; # like all exceptions until we have exec'd, this exception is pickled # and sent to the parent to raise in the calling process. # The parent uses this to decide how to treat that exception, # adjusting certain information about it as needed. # # Python 3.11.8 --- yes, a minor patch release --- stopped # letting the 'filename' parameter get set in the resulting # exception for many cases. We're not quite interpreting this # the same way the stdlib is, I'm sure, but this makes the stdlib # tests pass. # XXX: Technically we're doing a lot of stuff here that # may not be safe to do before a exec(), depending on the OS. # CPython 3 goes to great lengths to precompute a lot # of this info before the fork and pass it all to C functions that # try hard not to call things like malloc(). (Of course, # CPython 2 pretty much did what we're doing.) try: # Close parent's pipe ends if p2cwrite != -1: os.close(p2cwrite) if c2pread != -1: os.close(c2pread) if errread != -1: os.close(errread) os.close(errpipe_read) # When duping fds, if there arises a situation # where one of the fds is either 0, 1 or 2, it # is possible that it is overwritten (#12607). if c2pwrite == 0: c2pwrite = os.dup(c2pwrite) _set_inheritable(c2pwrite, False) while errwrite in (0, 1): errwrite = os.dup(errwrite) _set_inheritable(errwrite, False) # Dup fds for child def _dup2(existing, desired): # dup2() removes the CLOEXEC flag but # we must do it ourselves if dup2() # would be a no-op (issue #10806). if existing == desired: self._set_cloexec_flag(existing, False) elif existing != -1: os.dup2(existing, desired) try: self._remove_nonblock_flag(desired) except OSError: # Ignore EBADF, it may not actually be # open yet. # Tested beginning in 3.7.0b3 test_subprocess.py pass _dup2(p2cread, 0) _dup2(c2pwrite, 1) _dup2(errwrite, 2) # Close pipe fds. Make sure we don't close the # same fd more than once, or standard fds. if not True: closed = set([None]) for fd in (p2cread, c2pwrite, errwrite): if fd not in closed and fd > 2: os.close(fd) closed.add(fd) # Python 3 (with a working set_inheritable): # We no longer manually close p2cread, # c2pwrite, and errwrite here as # _close_open_fds takes care when it is # not already non-inheritable. if cwd is not None: try: os.chdir(cwd) except OSError as e: e._failed_chdir = True raise # Python 3.9 if umask >= 0: os.umask(umask) # XXX: CPython does _Py_RestoreSignals here. # Then setsid() based on ??? try: if gids: os.setgroups(gids) if gid: os.setregid(gid, gid) if uid: os.setreuid(uid, uid) if process_group is not None: os.setpgid(0, process_group) except OSError as e: e._failed_chuser = True raise if preexec_fn: preexec_fn() # Close all other fds, if asked for. This must be done # after preexec_fn runs. if close_fds: fds_to_keep = set(pass_fds) fds_to_keep.add(errpipe_write) self._close_fds(fds_to_keep, errpipe_write) if restore_signals: # restore the documented signals back to sig_dfl; # not all will be defined on every platform for sig in 'SIGPIPE', 'SIGXFZ', 'SIGXFSZ': sig = getattr(signal, sig, None) if sig is not None: signal.signal(sig, signal.SIG_DFL) if start_new_session: os.setsid() try: if env is None: os.execvp(executable, args) else: # Python 3.6 started testing for # bytes values in the env; it also # started encoding strs using # fsencode and using a lower-level # API that takes a list of keys # and values. We don't have access # to that API, so we go the reverse direction. env = {os.fsdecode(k) if isinstance(k, bytes) else k: os.fsdecode(v) if isinstance(v, bytes) else v for k, v in env.items()} os.execvpe(executable, args, env) except OSError as e: e._failed_exec = True raise except: exc_type, exc_value, tb = sys.exc_info() # Save the traceback and attach it to the exception object exc_lines = traceback.format_exception(exc_type, exc_value, tb) exc_value.child_traceback = ''.join(exc_lines) os.write(errpipe_write, pickle.dumps(exc_value)) finally: # Make sure that the process exits no matter what. # The return code does not matter much as it won't be # reported to the application os._exit(1) # Parent self._child_created = True if gc_was_enabled: gc.enable() finally: # be sure the FD is closed no matter what os.close(errpipe_write) # self._devnull is not always defined. devnull_fd = getattr(self, '_devnull', None) if p2cread != -1 and p2cwrite != -1 and p2cread != devnull_fd: os.close(p2cread) if c2pwrite != -1 and c2pread != -1 and c2pwrite != devnull_fd: os.close(c2pwrite) if errwrite != -1 and errread != -1 and errwrite != devnull_fd: os.close(errwrite) if devnull_fd is not None: os.close(devnull_fd) # Prevent a double close of these fds from __init__ on error. self._closed_child_pipe_fds = True # Wait for exec to fail or succeed; possibly raising exception errpipe_read = FileObject(errpipe_read, 'rb') data = errpipe_read.read() finally: try: if hasattr(errpipe_read, 'close'): errpipe_read.close() else: os.close(errpipe_read) except OSError: # Especially on PyPy, we sometimes see the above # `os.close(errpipe_read)` raise an OSError. # It's not entirely clear why, but it happens in # InterprocessSignalTests.test_main sometimes, which must mean # we have some sort of race condition. pass finally: errpipe_read = -1 if data != b"": self.wait() child_exception = pickle.loads(data) for fd in (p2cwrite, c2pread, errread): if fd is not None and fd != -1: os.close(fd) if isinstance(child_exception, OSError): child_exception.filename = executable if hasattr(child_exception, '_failed_chdir'): child_exception.filename = cwd if getattr(child_exception, '_failed_chuser', False): child_exception.filename = None > raise child_exception E OSError: [Errno 8] Exec format error: 'locust' /usr/lib/python3/dist-packages/gevent/subprocess.py:1838: OSError ___ StandaloneIntegrationTests.test_spawing_with_fixed_multiple_locustfiles ____ self = def test_spawing_with_fixed_multiple_locustfiles(self): with mock_locustfile(content=MOCK_LOCUSTFILE_CONTENT_A) as mocked1: with mock_locustfile(content=MOCK_LOCUSTFILE_CONTENT_B) as mocked2: proc = subprocess.Popen( " ".join( [ "locust", "-f", f"{mocked1.file_path},{mocked2.file_path}", "--headless", "--run-time", "5s", "-u", "10", "-r", "10", "--loglevel", "INFO", ] ), stderr=STDOUT, stdout=PIPE, shell=True, text=True, ) output = proc.communicate()[0] > self.assertIn("Ramping to 10 users at a rate of 10.00 per second", output) E AssertionError: 'Ramping to 10 users at a rate of 10.00 per second' not found in '/build/reproducible-path/locust-2.24.0/debian/locust: line 2: from: command not found\n/build/reproducible-path/locust-2.24.0/debian/locust: line 5: syntax error: unexpected end of file\n' locust/test/test_main.py:1022: AssertionError _____________ StandaloneIntegrationTests.test_spawning_with_fixed ______________ self = def test_spawning_with_fixed(self): LOCUSTFILE_CONTENT = textwrap.dedent( """ from locust import User, task, constant class User1(User): fixed_count = 2 wait_time = constant(1) @task def t(self): print("Test task is running") class User2(User): wait_time = constant(1) @task def t(self): print("Test task is running") class User3(User): wait_time = constant(1) @task def t(self): print("Test task is running") """ ) with mock_locustfile(content=LOCUSTFILE_CONTENT) as mocked: proc = subprocess.Popen( " ".join( [ "locust", "-f", mocked.file_path, "--headless", "--run-time", "5s", "-u", "10", "-r", "10", "--loglevel", "INFO", ] ), stderr=STDOUT, stdout=PIPE, shell=True, text=True, ) output = proc.communicate()[0] > self.assertIn("Ramping to 10 users at a rate of 10.00 per second", output) E AssertionError: 'Ramping to 10 users at a rate of 10.00 per second' not found in '/build/reproducible-path/locust-2.24.0/debian/locust: line 2: from: command not found\n/build/reproducible-path/locust-2.24.0/debian/locust: line 5: syntax error: unexpected end of file\n' locust/test/test_main.py:987: AssertionError _________________ StandaloneIntegrationTests.test_web_options __________________ self = @unittest.skipIf(platform.system() == "Darwin", reason="Messy on macOS on GH") @unittest.skipIf(os.name == "nt", reason="Signal handling on windows is hard") def test_web_options(self): port = get_free_tcp_port() if platform.system() != "Darwin": # MacOS only sets up the loopback interface for 127.0.0.1 and not for 127.*.*.*, so we cant test this with mock_locustfile() as mocked: > proc = subprocess.Popen( ["locust", "-f", mocked.file_path, "--web-host", "127.0.0.2", "--web-port", str(port)], stdout=PIPE, stderr=PIPE, ) locust/test/test_main.py:838: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3/dist-packages/gevent/subprocess.py:808: in __init__ self._execute_child(args, executable, preexec_fn, close_fds, _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = args = ['locust', '-f', '/build/reproducible-path/locust-2.24.0/locust/test/mock_locustfile_1715255810_7718437_28341.py', '--web-host', '127.0.0.2', '--web-port', ...] executable = 'locust', preexec_fn = None, close_fds = True, pass_fds = () cwd = None, env = None, universal_newlines = None, startupinfo = None creationflags = 0, shell = False, p2cread = -1, p2cwrite = -1, c2pread = 11 c2pwrite = 81, errread = 82, errwrite = 83, restore_signals = True, gid = None gids = None, uid = None, umask = -1, start_new_session = False process_group = None def _execute_child(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, universal_newlines, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, restore_signals, gid, gids, uid, umask, start_new_session, process_group): """Execute program (POSIX version)""" if isinstance(args, (str, bytes)): args = [args] elif isinstance(args, PathLike): if shell: raise TypeError('path-like args is not allowed when ' 'shell is true') args = [fsencode(args)] # os.PathLike -> [str] else: args = list(args) if shell: # On Android the default shell is at '/system/bin/sh'. unix_shell = ( '/system/bin/sh' if hasattr(sys, 'getandroidapilevel') else '/bin/sh' ) args = [unix_shell, "-c"] + args if executable: args[0] = executable if executable is None: executable = args[0] self._loop.install_sigchld() # For transferring possible exec failure from child to parent # The first char specifies the exception type: 0 means # OSError, 1 means some other error. errpipe_read, errpipe_write = self.pipe_cloexec() # errpipe_write must not be in the standard io 0, 1, or 2 fd range. low_fds_to_close = [] while errpipe_write < 3: low_fds_to_close.append(errpipe_write) errpipe_write = os.dup(errpipe_write) for low_fd in low_fds_to_close: os.close(low_fd) try: try: gc_was_enabled = gc.isenabled() # Disable gc to avoid bug where gc -> file_dealloc -> # write to stderr -> hang. http://bugs.python.org/issue1336 gc.disable() try: self.pid = fork_and_watch(self._on_child, self._loop, True, fork) except: if gc_was_enabled: gc.enable() raise if self.pid == 0: # Child # In various places on the child side of things, we catch OSError # and add attributes to it that detail where in the process we failed; # like all exceptions until we have exec'd, this exception is pickled # and sent to the parent to raise in the calling process. # The parent uses this to decide how to treat that exception, # adjusting certain information about it as needed. # # Python 3.11.8 --- yes, a minor patch release --- stopped # letting the 'filename' parameter get set in the resulting # exception for many cases. We're not quite interpreting this # the same way the stdlib is, I'm sure, but this makes the stdlib # tests pass. # XXX: Technically we're doing a lot of stuff here that # may not be safe to do before a exec(), depending on the OS. # CPython 3 goes to great lengths to precompute a lot # of this info before the fork and pass it all to C functions that # try hard not to call things like malloc(). (Of course, # CPython 2 pretty much did what we're doing.) try: # Close parent's pipe ends if p2cwrite != -1: os.close(p2cwrite) if c2pread != -1: os.close(c2pread) if errread != -1: os.close(errread) os.close(errpipe_read) # When duping fds, if there arises a situation # where one of the fds is either 0, 1 or 2, it # is possible that it is overwritten (#12607). if c2pwrite == 0: c2pwrite = os.dup(c2pwrite) _set_inheritable(c2pwrite, False) while errwrite in (0, 1): errwrite = os.dup(errwrite) _set_inheritable(errwrite, False) # Dup fds for child def _dup2(existing, desired): # dup2() removes the CLOEXEC flag but # we must do it ourselves if dup2() # would be a no-op (issue #10806). if existing == desired: self._set_cloexec_flag(existing, False) elif existing != -1: os.dup2(existing, desired) try: self._remove_nonblock_flag(desired) except OSError: # Ignore EBADF, it may not actually be # open yet. # Tested beginning in 3.7.0b3 test_subprocess.py pass _dup2(p2cread, 0) _dup2(c2pwrite, 1) _dup2(errwrite, 2) # Close pipe fds. Make sure we don't close the # same fd more than once, or standard fds. if not True: closed = set([None]) for fd in (p2cread, c2pwrite, errwrite): if fd not in closed and fd > 2: os.close(fd) closed.add(fd) # Python 3 (with a working set_inheritable): # We no longer manually close p2cread, # c2pwrite, and errwrite here as # _close_open_fds takes care when it is # not already non-inheritable. if cwd is not None: try: os.chdir(cwd) except OSError as e: e._failed_chdir = True raise # Python 3.9 if umask >= 0: os.umask(umask) # XXX: CPython does _Py_RestoreSignals here. # Then setsid() based on ??? try: if gids: os.setgroups(gids) if gid: os.setregid(gid, gid) if uid: os.setreuid(uid, uid) if process_group is not None: os.setpgid(0, process_group) except OSError as e: e._failed_chuser = True raise if preexec_fn: preexec_fn() # Close all other fds, if asked for. This must be done # after preexec_fn runs. if close_fds: fds_to_keep = set(pass_fds) fds_to_keep.add(errpipe_write) self._close_fds(fds_to_keep, errpipe_write) if restore_signals: # restore the documented signals back to sig_dfl; # not all will be defined on every platform for sig in 'SIGPIPE', 'SIGXFZ', 'SIGXFSZ': sig = getattr(signal, sig, None) if sig is not None: signal.signal(sig, signal.SIG_DFL) if start_new_session: os.setsid() try: if env is None: os.execvp(executable, args) else: # Python 3.6 started testing for # bytes values in the env; it also # started encoding strs using # fsencode and using a lower-level # API that takes a list of keys # and values. We don't have access # to that API, so we go the reverse direction. env = {os.fsdecode(k) if isinstance(k, bytes) else k: os.fsdecode(v) if isinstance(v, bytes) else v for k, v in env.items()} os.execvpe(executable, args, env) except OSError as e: e._failed_exec = True raise except: exc_type, exc_value, tb = sys.exc_info() # Save the traceback and attach it to the exception object exc_lines = traceback.format_exception(exc_type, exc_value, tb) exc_value.child_traceback = ''.join(exc_lines) os.write(errpipe_write, pickle.dumps(exc_value)) finally: # Make sure that the process exits no matter what. # The return code does not matter much as it won't be # reported to the application os._exit(1) # Parent self._child_created = True if gc_was_enabled: gc.enable() finally: # be sure the FD is closed no matter what os.close(errpipe_write) # self._devnull is not always defined. devnull_fd = getattr(self, '_devnull', None) if p2cread != -1 and p2cwrite != -1 and p2cread != devnull_fd: os.close(p2cread) if c2pwrite != -1 and c2pread != -1 and c2pwrite != devnull_fd: os.close(c2pwrite) if errwrite != -1 and errread != -1 and errwrite != devnull_fd: os.close(errwrite) if devnull_fd is not None: os.close(devnull_fd) # Prevent a double close of these fds from __init__ on error. self._closed_child_pipe_fds = True # Wait for exec to fail or succeed; possibly raising exception errpipe_read = FileObject(errpipe_read, 'rb') data = errpipe_read.read() finally: try: if hasattr(errpipe_read, 'close'): errpipe_read.close() else: os.close(errpipe_read) except OSError: # Especially on PyPy, we sometimes see the above # `os.close(errpipe_read)` raise an OSError. # It's not entirely clear why, but it happens in # InterprocessSignalTests.test_main sometimes, which must mean # we have some sort of race condition. pass finally: errpipe_read = -1 if data != b"": self.wait() child_exception = pickle.loads(data) for fd in (p2cwrite, c2pread, errread): if fd is not None and fd != -1: os.close(fd) if isinstance(child_exception, OSError): child_exception.filename = executable if hasattr(child_exception, '_failed_chdir'): child_exception.filename = cwd if getattr(child_exception, '_failed_chuser', False): child_exception.filename = None > raise child_exception E OSError: [Errno 8] Exec format error: 'locust' /usr/lib/python3/dist-packages/gevent/subprocess.py:1838: OSError __________________ StandaloneIntegrationTests.test_webserver ___________________ self = @unittest.skipIf(os.name == "nt", reason="Signal handling on windows is hard") def test_webserver(self): with temporary_file( content=textwrap.dedent( """ from locust import User, task, constant, events class TestUser(User): wait_time = constant(3) @task def my_task(self): print("running my_task()") """ ) ) as file_path: > proc = subprocess.Popen(["locust", "-f", file_path], stdout=PIPE, stderr=PIPE, text=True) locust/test/test_main.py:206: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3/dist-packages/gevent/subprocess.py:808: in __init__ self._execute_child(args, executable, preexec_fn, close_fds, _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = args = ['locust', '-f', '/tmp/tmpbrdu7sbt_locustfile.py'], executable = 'locust' preexec_fn = None, close_fds = True, pass_fds = (), cwd = None, env = None universal_newlines = None, startupinfo = None, creationflags = 0, shell = False p2cread = -1, p2cwrite = -1, c2pread = 11, c2pwrite = 81, errread = 82 errwrite = 83, restore_signals = True, gid = None, gids = None, uid = None umask = -1, start_new_session = False, process_group = None def _execute_child(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, universal_newlines, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, restore_signals, gid, gids, uid, umask, start_new_session, process_group): """Execute program (POSIX version)""" if isinstance(args, (str, bytes)): args = [args] elif isinstance(args, PathLike): if shell: raise TypeError('path-like args is not allowed when ' 'shell is true') args = [fsencode(args)] # os.PathLike -> [str] else: args = list(args) if shell: # On Android the default shell is at '/system/bin/sh'. unix_shell = ( '/system/bin/sh' if hasattr(sys, 'getandroidapilevel') else '/bin/sh' ) args = [unix_shell, "-c"] + args if executable: args[0] = executable if executable is None: executable = args[0] self._loop.install_sigchld() # For transferring possible exec failure from child to parent # The first char specifies the exception type: 0 means # OSError, 1 means some other error. errpipe_read, errpipe_write = self.pipe_cloexec() # errpipe_write must not be in the standard io 0, 1, or 2 fd range. low_fds_to_close = [] while errpipe_write < 3: low_fds_to_close.append(errpipe_write) errpipe_write = os.dup(errpipe_write) for low_fd in low_fds_to_close: os.close(low_fd) try: try: gc_was_enabled = gc.isenabled() # Disable gc to avoid bug where gc -> file_dealloc -> # write to stderr -> hang. http://bugs.python.org/issue1336 gc.disable() try: self.pid = fork_and_watch(self._on_child, self._loop, True, fork) except: if gc_was_enabled: gc.enable() raise if self.pid == 0: # Child # In various places on the child side of things, we catch OSError # and add attributes to it that detail where in the process we failed; # like all exceptions until we have exec'd, this exception is pickled # and sent to the parent to raise in the calling process. # The parent uses this to decide how to treat that exception, # adjusting certain information about it as needed. # # Python 3.11.8 --- yes, a minor patch release --- stopped # letting the 'filename' parameter get set in the resulting # exception for many cases. We're not quite interpreting this # the same way the stdlib is, I'm sure, but this makes the stdlib # tests pass. # XXX: Technically we're doing a lot of stuff here that # may not be safe to do before a exec(), depending on the OS. # CPython 3 goes to great lengths to precompute a lot # of this info before the fork and pass it all to C functions that # try hard not to call things like malloc(). (Of course, # CPython 2 pretty much did what we're doing.) try: # Close parent's pipe ends if p2cwrite != -1: os.close(p2cwrite) if c2pread != -1: os.close(c2pread) if errread != -1: os.close(errread) os.close(errpipe_read) # When duping fds, if there arises a situation # where one of the fds is either 0, 1 or 2, it # is possible that it is overwritten (#12607). if c2pwrite == 0: c2pwrite = os.dup(c2pwrite) _set_inheritable(c2pwrite, False) while errwrite in (0, 1): errwrite = os.dup(errwrite) _set_inheritable(errwrite, False) # Dup fds for child def _dup2(existing, desired): # dup2() removes the CLOEXEC flag but # we must do it ourselves if dup2() # would be a no-op (issue #10806). if existing == desired: self._set_cloexec_flag(existing, False) elif existing != -1: os.dup2(existing, desired) try: self._remove_nonblock_flag(desired) except OSError: # Ignore EBADF, it may not actually be # open yet. # Tested beginning in 3.7.0b3 test_subprocess.py pass _dup2(p2cread, 0) _dup2(c2pwrite, 1) _dup2(errwrite, 2) # Close pipe fds. Make sure we don't close the # same fd more than once, or standard fds. if not True: closed = set([None]) for fd in (p2cread, c2pwrite, errwrite): if fd not in closed and fd > 2: os.close(fd) closed.add(fd) # Python 3 (with a working set_inheritable): # We no longer manually close p2cread, # c2pwrite, and errwrite here as # _close_open_fds takes care when it is # not already non-inheritable. if cwd is not None: try: os.chdir(cwd) except OSError as e: e._failed_chdir = True raise # Python 3.9 if umask >= 0: os.umask(umask) # XXX: CPython does _Py_RestoreSignals here. # Then setsid() based on ??? try: if gids: os.setgroups(gids) if gid: os.setregid(gid, gid) if uid: os.setreuid(uid, uid) if process_group is not None: os.setpgid(0, process_group) except OSError as e: e._failed_chuser = True raise if preexec_fn: preexec_fn() # Close all other fds, if asked for. This must be done # after preexec_fn runs. if close_fds: fds_to_keep = set(pass_fds) fds_to_keep.add(errpipe_write) self._close_fds(fds_to_keep, errpipe_write) if restore_signals: # restore the documented signals back to sig_dfl; # not all will be defined on every platform for sig in 'SIGPIPE', 'SIGXFZ', 'SIGXFSZ': sig = getattr(signal, sig, None) if sig is not None: signal.signal(sig, signal.SIG_DFL) if start_new_session: os.setsid() try: if env is None: os.execvp(executable, args) else: # Python 3.6 started testing for # bytes values in the env; it also # started encoding strs using # fsencode and using a lower-level # API that takes a list of keys # and values. We don't have access # to that API, so we go the reverse direction. env = {os.fsdecode(k) if isinstance(k, bytes) else k: os.fsdecode(v) if isinstance(v, bytes) else v for k, v in env.items()} os.execvpe(executable, args, env) except OSError as e: e._failed_exec = True raise except: exc_type, exc_value, tb = sys.exc_info() # Save the traceback and attach it to the exception object exc_lines = traceback.format_exception(exc_type, exc_value, tb) exc_value.child_traceback = ''.join(exc_lines) os.write(errpipe_write, pickle.dumps(exc_value)) finally: # Make sure that the process exits no matter what. # The return code does not matter much as it won't be # reported to the application os._exit(1) # Parent self._child_created = True if gc_was_enabled: gc.enable() finally: # be sure the FD is closed no matter what os.close(errpipe_write) # self._devnull is not always defined. devnull_fd = getattr(self, '_devnull', None) if p2cread != -1 and p2cwrite != -1 and p2cread != devnull_fd: os.close(p2cread) if c2pwrite != -1 and c2pread != -1 and c2pwrite != devnull_fd: os.close(c2pwrite) if errwrite != -1 and errread != -1 and errwrite != devnull_fd: os.close(errwrite) if devnull_fd is not None: os.close(devnull_fd) # Prevent a double close of these fds from __init__ on error. self._closed_child_pipe_fds = True # Wait for exec to fail or succeed; possibly raising exception errpipe_read = FileObject(errpipe_read, 'rb') data = errpipe_read.read() finally: try: if hasattr(errpipe_read, 'close'): errpipe_read.close() else: os.close(errpipe_read) except OSError: # Especially on PyPy, we sometimes see the above # `os.close(errpipe_read)` raise an OSError. # It's not entirely clear why, but it happens in # InterprocessSignalTests.test_main sometimes, which must mean # we have some sort of race condition. pass finally: errpipe_read = -1 if data != b"": self.wait() child_exception = pickle.loads(data) for fd in (p2cwrite, c2pread, errread): if fd is not None and fd != -1: os.close(fd) if isinstance(child_exception, OSError): child_exception.filename = executable if hasattr(child_exception, '_failed_chdir'): child_exception.filename = cwd if getattr(child_exception, '_failed_chuser', False): child_exception.filename = None > raise child_exception E OSError: [Errno 8] Exec format error: 'locust' /usr/lib/python3/dist-packages/gevent/subprocess.py:1838: OSError ________ StandaloneIntegrationTests.test_webserver_multiple_locustfiles ________ self = @unittest.skipIf(os.name == "nt", reason="Signal handling on windows is hard") def test_webserver_multiple_locustfiles(self): with mock_locustfile(content=MOCK_LOCUSTFILE_CONTENT_A) as mocked1: with mock_locustfile(content=MOCK_LOCUSTFILE_CONTENT_B) as mocked2: > proc = subprocess.Popen( ["locust", "-f", f"{mocked1.file_path},{mocked2.file_path}"], stdout=PIPE, stderr=PIPE, text=True ) locust/test/test_main.py:297: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3/dist-packages/gevent/subprocess.py:808: in __init__ self._execute_child(args, executable, preexec_fn, close_fds, _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = args = ['locust', '-f', '/build/reproducible-path/locust-2.24.0/locust/test/mock_locustfile_1715255811_151679_79043.py,/build/reproducible-path/locust-2.24.0/locust/test/mock_locustfile_1715255811_151833_62155.py'] executable = 'locust', preexec_fn = None, close_fds = True, pass_fds = () cwd = None, env = None, universal_newlines = None, startupinfo = None creationflags = 0, shell = False, p2cread = -1, p2cwrite = -1, c2pread = 11 c2pwrite = 81, errread = 82, errwrite = 83, restore_signals = True, gid = None gids = None, uid = None, umask = -1, start_new_session = False process_group = None def _execute_child(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, universal_newlines, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, restore_signals, gid, gids, uid, umask, start_new_session, process_group): """Execute program (POSIX version)""" if isinstance(args, (str, bytes)): args = [args] elif isinstance(args, PathLike): if shell: raise TypeError('path-like args is not allowed when ' 'shell is true') args = [fsencode(args)] # os.PathLike -> [str] else: args = list(args) if shell: # On Android the default shell is at '/system/bin/sh'. unix_shell = ( '/system/bin/sh' if hasattr(sys, 'getandroidapilevel') else '/bin/sh' ) args = [unix_shell, "-c"] + args if executable: args[0] = executable if executable is None: executable = args[0] self._loop.install_sigchld() # For transferring possible exec failure from child to parent # The first char specifies the exception type: 0 means # OSError, 1 means some other error. errpipe_read, errpipe_write = self.pipe_cloexec() # errpipe_write must not be in the standard io 0, 1, or 2 fd range. low_fds_to_close = [] while errpipe_write < 3: low_fds_to_close.append(errpipe_write) errpipe_write = os.dup(errpipe_write) for low_fd in low_fds_to_close: os.close(low_fd) try: try: gc_was_enabled = gc.isenabled() # Disable gc to avoid bug where gc -> file_dealloc -> # write to stderr -> hang. http://bugs.python.org/issue1336 gc.disable() try: self.pid = fork_and_watch(self._on_child, self._loop, True, fork) except: if gc_was_enabled: gc.enable() raise if self.pid == 0: # Child # In various places on the child side of things, we catch OSError # and add attributes to it that detail where in the process we failed; # like all exceptions until we have exec'd, this exception is pickled # and sent to the parent to raise in the calling process. # The parent uses this to decide how to treat that exception, # adjusting certain information about it as needed. # # Python 3.11.8 --- yes, a minor patch release --- stopped # letting the 'filename' parameter get set in the resulting # exception for many cases. We're not quite interpreting this # the same way the stdlib is, I'm sure, but this makes the stdlib # tests pass. # XXX: Technically we're doing a lot of stuff here that # may not be safe to do before a exec(), depending on the OS. # CPython 3 goes to great lengths to precompute a lot # of this info before the fork and pass it all to C functions that # try hard not to call things like malloc(). (Of course, # CPython 2 pretty much did what we're doing.) try: # Close parent's pipe ends if p2cwrite != -1: os.close(p2cwrite) if c2pread != -1: os.close(c2pread) if errread != -1: os.close(errread) os.close(errpipe_read) # When duping fds, if there arises a situation # where one of the fds is either 0, 1 or 2, it # is possible that it is overwritten (#12607). if c2pwrite == 0: c2pwrite = os.dup(c2pwrite) _set_inheritable(c2pwrite, False) while errwrite in (0, 1): errwrite = os.dup(errwrite) _set_inheritable(errwrite, False) # Dup fds for child def _dup2(existing, desired): # dup2() removes the CLOEXEC flag but # we must do it ourselves if dup2() # would be a no-op (issue #10806). if existing == desired: self._set_cloexec_flag(existing, False) elif existing != -1: os.dup2(existing, desired) try: self._remove_nonblock_flag(desired) except OSError: # Ignore EBADF, it may not actually be # open yet. # Tested beginning in 3.7.0b3 test_subprocess.py pass _dup2(p2cread, 0) _dup2(c2pwrite, 1) _dup2(errwrite, 2) # Close pipe fds. Make sure we don't close the # same fd more than once, or standard fds. if not True: closed = set([None]) for fd in (p2cread, c2pwrite, errwrite): if fd not in closed and fd > 2: os.close(fd) closed.add(fd) # Python 3 (with a working set_inheritable): # We no longer manually close p2cread, # c2pwrite, and errwrite here as # _close_open_fds takes care when it is # not already non-inheritable. if cwd is not None: try: os.chdir(cwd) except OSError as e: e._failed_chdir = True raise # Python 3.9 if umask >= 0: os.umask(umask) # XXX: CPython does _Py_RestoreSignals here. # Then setsid() based on ??? try: if gids: os.setgroups(gids) if gid: os.setregid(gid, gid) if uid: os.setreuid(uid, uid) if process_group is not None: os.setpgid(0, process_group) except OSError as e: e._failed_chuser = True raise if preexec_fn: preexec_fn() # Close all other fds, if asked for. This must be done # after preexec_fn runs. if close_fds: fds_to_keep = set(pass_fds) fds_to_keep.add(errpipe_write) self._close_fds(fds_to_keep, errpipe_write) if restore_signals: # restore the documented signals back to sig_dfl; # not all will be defined on every platform for sig in 'SIGPIPE', 'SIGXFZ', 'SIGXFSZ': sig = getattr(signal, sig, None) if sig is not None: signal.signal(sig, signal.SIG_DFL) if start_new_session: os.setsid() try: if env is None: os.execvp(executable, args) else: # Python 3.6 started testing for # bytes values in the env; it also # started encoding strs using # fsencode and using a lower-level # API that takes a list of keys # and values. We don't have access # to that API, so we go the reverse direction. env = {os.fsdecode(k) if isinstance(k, bytes) else k: os.fsdecode(v) if isinstance(v, bytes) else v for k, v in env.items()} os.execvpe(executable, args, env) except OSError as e: e._failed_exec = True raise except: exc_type, exc_value, tb = sys.exc_info() # Save the traceback and attach it to the exception object exc_lines = traceback.format_exception(exc_type, exc_value, tb) exc_value.child_traceback = ''.join(exc_lines) os.write(errpipe_write, pickle.dumps(exc_value)) finally: # Make sure that the process exits no matter what. # The return code does not matter much as it won't be # reported to the application os._exit(1) # Parent self._child_created = True if gc_was_enabled: gc.enable() finally: # be sure the FD is closed no matter what os.close(errpipe_write) # self._devnull is not always defined. devnull_fd = getattr(self, '_devnull', None) if p2cread != -1 and p2cwrite != -1 and p2cread != devnull_fd: os.close(p2cread) if c2pwrite != -1 and c2pread != -1 and c2pwrite != devnull_fd: os.close(c2pwrite) if errwrite != -1 and errread != -1 and errwrite != devnull_fd: os.close(errwrite) if devnull_fd is not None: os.close(devnull_fd) # Prevent a double close of these fds from __init__ on error. self._closed_child_pipe_fds = True # Wait for exec to fail or succeed; possibly raising exception errpipe_read = FileObject(errpipe_read, 'rb') data = errpipe_read.read() finally: try: if hasattr(errpipe_read, 'close'): errpipe_read.close() else: os.close(errpipe_read) except OSError: # Especially on PyPy, we sometimes see the above # `os.close(errpipe_read)` raise an OSError. # It's not entirely clear why, but it happens in # InterprocessSignalTests.test_main sometimes, which must mean # we have some sort of race condition. pass finally: errpipe_read = -1 if data != b"": self.wait() child_exception = pickle.loads(data) for fd in (p2cwrite, c2pread, errread): if fd is not None and fd != -1: os.close(fd) if isinstance(child_exception, OSError): child_exception.filename = executable if hasattr(child_exception, '_failed_chdir'): child_exception.filename = cwd if getattr(child_exception, '_failed_chuser', False): child_exception.filename = None > raise child_exception E OSError: [Errno 8] Exec format error: 'locust' /usr/lib/python3/dist-packages/gevent/subprocess.py:1838: OSError _ StandaloneIntegrationTests.test_webserver_multiple_locustfiles_in_directory __ self = @unittest.skipIf(os.name == "nt", reason="Signal handling on windows is hard") def test_webserver_multiple_locustfiles_in_directory(self): with TemporaryDirectory() as temp_dir: with mock_locustfile(content=MOCK_LOCUSTFILE_CONTENT_A, dir=temp_dir): with mock_locustfile(content=MOCK_LOCUSTFILE_CONTENT_B, dir=temp_dir): > proc = subprocess.Popen(["locust", "-f", temp_dir], stdout=PIPE, stderr=PIPE, text=True) locust/test/test_main.py:314: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3/dist-packages/gevent/subprocess.py:808: in __init__ self._execute_child(args, executable, preexec_fn, close_fds, _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = args = ['locust', '-f', '/tmp/tmpw9z5ze0u'], executable = 'locust' preexec_fn = None, close_fds = True, pass_fds = (), cwd = None, env = None universal_newlines = None, startupinfo = None, creationflags = 0, shell = False p2cread = -1, p2cwrite = -1, c2pread = 11, c2pwrite = 81, errread = 82 errwrite = 83, restore_signals = True, gid = None, gids = None, uid = None umask = -1, start_new_session = False, process_group = None def _execute_child(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, universal_newlines, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, restore_signals, gid, gids, uid, umask, start_new_session, process_group): """Execute program (POSIX version)""" if isinstance(args, (str, bytes)): args = [args] elif isinstance(args, PathLike): if shell: raise TypeError('path-like args is not allowed when ' 'shell is true') args = [fsencode(args)] # os.PathLike -> [str] else: args = list(args) if shell: # On Android the default shell is at '/system/bin/sh'. unix_shell = ( '/system/bin/sh' if hasattr(sys, 'getandroidapilevel') else '/bin/sh' ) args = [unix_shell, "-c"] + args if executable: args[0] = executable if executable is None: executable = args[0] self._loop.install_sigchld() # For transferring possible exec failure from child to parent # The first char specifies the exception type: 0 means # OSError, 1 means some other error. errpipe_read, errpipe_write = self.pipe_cloexec() # errpipe_write must not be in the standard io 0, 1, or 2 fd range. low_fds_to_close = [] while errpipe_write < 3: low_fds_to_close.append(errpipe_write) errpipe_write = os.dup(errpipe_write) for low_fd in low_fds_to_close: os.close(low_fd) try: try: gc_was_enabled = gc.isenabled() # Disable gc to avoid bug where gc -> file_dealloc -> # write to stderr -> hang. http://bugs.python.org/issue1336 gc.disable() try: self.pid = fork_and_watch(self._on_child, self._loop, True, fork) except: if gc_was_enabled: gc.enable() raise if self.pid == 0: # Child # In various places on the child side of things, we catch OSError # and add attributes to it that detail where in the process we failed; # like all exceptions until we have exec'd, this exception is pickled # and sent to the parent to raise in the calling process. # The parent uses this to decide how to treat that exception, # adjusting certain information about it as needed. # # Python 3.11.8 --- yes, a minor patch release --- stopped # letting the 'filename' parameter get set in the resulting # exception for many cases. We're not quite interpreting this # the same way the stdlib is, I'm sure, but this makes the stdlib # tests pass. # XXX: Technically we're doing a lot of stuff here that # may not be safe to do before a exec(), depending on the OS. # CPython 3 goes to great lengths to precompute a lot # of this info before the fork and pass it all to C functions that # try hard not to call things like malloc(). (Of course, # CPython 2 pretty much did what we're doing.) try: # Close parent's pipe ends if p2cwrite != -1: os.close(p2cwrite) if c2pread != -1: os.close(c2pread) if errread != -1: os.close(errread) os.close(errpipe_read) # When duping fds, if there arises a situation # where one of the fds is either 0, 1 or 2, it # is possible that it is overwritten (#12607). if c2pwrite == 0: c2pwrite = os.dup(c2pwrite) _set_inheritable(c2pwrite, False) while errwrite in (0, 1): errwrite = os.dup(errwrite) _set_inheritable(errwrite, False) # Dup fds for child def _dup2(existing, desired): # dup2() removes the CLOEXEC flag but # we must do it ourselves if dup2() # would be a no-op (issue #10806). if existing == desired: self._set_cloexec_flag(existing, False) elif existing != -1: os.dup2(existing, desired) try: self._remove_nonblock_flag(desired) except OSError: # Ignore EBADF, it may not actually be # open yet. # Tested beginning in 3.7.0b3 test_subprocess.py pass _dup2(p2cread, 0) _dup2(c2pwrite, 1) _dup2(errwrite, 2) # Close pipe fds. Make sure we don't close the # same fd more than once, or standard fds. if not True: closed = set([None]) for fd in (p2cread, c2pwrite, errwrite): if fd not in closed and fd > 2: os.close(fd) closed.add(fd) # Python 3 (with a working set_inheritable): # We no longer manually close p2cread, # c2pwrite, and errwrite here as # _close_open_fds takes care when it is # not already non-inheritable. if cwd is not None: try: os.chdir(cwd) except OSError as e: e._failed_chdir = True raise # Python 3.9 if umask >= 0: os.umask(umask) # XXX: CPython does _Py_RestoreSignals here. # Then setsid() based on ??? try: if gids: os.setgroups(gids) if gid: os.setregid(gid, gid) if uid: os.setreuid(uid, uid) if process_group is not None: os.setpgid(0, process_group) except OSError as e: e._failed_chuser = True raise if preexec_fn: preexec_fn() # Close all other fds, if asked for. This must be done # after preexec_fn runs. if close_fds: fds_to_keep = set(pass_fds) fds_to_keep.add(errpipe_write) self._close_fds(fds_to_keep, errpipe_write) if restore_signals: # restore the documented signals back to sig_dfl; # not all will be defined on every platform for sig in 'SIGPIPE', 'SIGXFZ', 'SIGXFSZ': sig = getattr(signal, sig, None) if sig is not None: signal.signal(sig, signal.SIG_DFL) if start_new_session: os.setsid() try: if env is None: os.execvp(executable, args) else: # Python 3.6 started testing for # bytes values in the env; it also # started encoding strs using # fsencode and using a lower-level # API that takes a list of keys # and values. We don't have access # to that API, so we go the reverse direction. env = {os.fsdecode(k) if isinstance(k, bytes) else k: os.fsdecode(v) if isinstance(v, bytes) else v for k, v in env.items()} os.execvpe(executable, args, env) except OSError as e: e._failed_exec = True raise except: exc_type, exc_value, tb = sys.exc_info() # Save the traceback and attach it to the exception object exc_lines = traceback.format_exception(exc_type, exc_value, tb) exc_value.child_traceback = ''.join(exc_lines) os.write(errpipe_write, pickle.dumps(exc_value)) finally: # Make sure that the process exits no matter what. # The return code does not matter much as it won't be # reported to the application os._exit(1) # Parent self._child_created = True if gc_was_enabled: gc.enable() finally: # be sure the FD is closed no matter what os.close(errpipe_write) # self._devnull is not always defined. devnull_fd = getattr(self, '_devnull', None) if p2cread != -1 and p2cwrite != -1 and p2cread != devnull_fd: os.close(p2cread) if c2pwrite != -1 and c2pread != -1 and c2pwrite != devnull_fd: os.close(c2pwrite) if errwrite != -1 and errread != -1 and errwrite != devnull_fd: os.close(errwrite) if devnull_fd is not None: os.close(devnull_fd) # Prevent a double close of these fds from __init__ on error. self._closed_child_pipe_fds = True # Wait for exec to fail or succeed; possibly raising exception errpipe_read = FileObject(errpipe_read, 'rb') data = errpipe_read.read() finally: try: if hasattr(errpipe_read, 'close'): errpipe_read.close() else: os.close(errpipe_read) except OSError: # Especially on PyPy, we sometimes see the above # `os.close(errpipe_read)` raise an OSError. # It's not entirely clear why, but it happens in # InterprocessSignalTests.test_main sometimes, which must mean # we have some sort of race condition. pass finally: errpipe_read = -1 if data != b"": self.wait() child_exception = pickle.loads(data) for fd in (p2cwrite, c2pread, errread): if fd is not None and fd != -1: os.close(fd) if isinstance(child_exception, OSError): child_exception.filename = executable if hasattr(child_exception, '_failed_chdir'): child_exception.filename = cwd if getattr(child_exception, '_failed_chuser', False): child_exception.filename = None > raise child_exception E OSError: [Errno 8] Exec format error: 'locust' /usr/lib/python3/dist-packages/gevent/subprocess.py:1838: OSError __ StandaloneIntegrationTests.test_webserver_multiple_locustfiles_with_shape ___ self = @unittest.skipIf(os.name == "nt", reason="Signal handling on windows is hard") def test_webserver_multiple_locustfiles_with_shape(self): content = textwrap.dedent( """ from locust import User, task, between class TestUser2(User): wait_time = between(2, 4) @task def my_task(self): print("running my_task() again") """ ) with mock_locustfile(content=content) as mocked1: with temporary_file( content=textwrap.dedent( """ from locust import User, task, between, LoadTestShape class LoadTestShape(LoadTestShape): def tick(self): run_time = self.get_run_time() if run_time < 2: return (10, 1) return None class TestUser(User): wait_time = between(2, 4) @task def my_task(self): print("running my_task()") """ ) ) as mocked2: > proc = subprocess.Popen( ["locust", "-f", f"{mocked1.file_path},{mocked2}"], stdout=PIPE, stderr=PIPE, text=True ) locust/test/test_main.py:357: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3/dist-packages/gevent/subprocess.py:808: in __init__ self._execute_child(args, executable, preexec_fn, close_fds, _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = args = ['locust', '-f', '/build/reproducible-path/locust-2.24.0/locust/test/mock_locustfile_1715255811_554538_23276.py,/tmp/tmp1qwujxqf_locustfile.py'] executable = 'locust', preexec_fn = None, close_fds = True, pass_fds = () cwd = None, env = None, universal_newlines = None, startupinfo = None creationflags = 0, shell = False, p2cread = -1, p2cwrite = -1, c2pread = 11 c2pwrite = 81, errread = 82, errwrite = 83, restore_signals = True, gid = None gids = None, uid = None, umask = -1, start_new_session = False process_group = None def _execute_child(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, universal_newlines, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, restore_signals, gid, gids, uid, umask, start_new_session, process_group): """Execute program (POSIX version)""" if isinstance(args, (str, bytes)): args = [args] elif isinstance(args, PathLike): if shell: raise TypeError('path-like args is not allowed when ' 'shell is true') args = [fsencode(args)] # os.PathLike -> [str] else: args = list(args) if shell: # On Android the default shell is at '/system/bin/sh'. unix_shell = ( '/system/bin/sh' if hasattr(sys, 'getandroidapilevel') else '/bin/sh' ) args = [unix_shell, "-c"] + args if executable: args[0] = executable if executable is None: executable = args[0] self._loop.install_sigchld() # For transferring possible exec failure from child to parent # The first char specifies the exception type: 0 means # OSError, 1 means some other error. errpipe_read, errpipe_write = self.pipe_cloexec() # errpipe_write must not be in the standard io 0, 1, or 2 fd range. low_fds_to_close = [] while errpipe_write < 3: low_fds_to_close.append(errpipe_write) errpipe_write = os.dup(errpipe_write) for low_fd in low_fds_to_close: os.close(low_fd) try: try: gc_was_enabled = gc.isenabled() # Disable gc to avoid bug where gc -> file_dealloc -> # write to stderr -> hang. http://bugs.python.org/issue1336 gc.disable() try: self.pid = fork_and_watch(self._on_child, self._loop, True, fork) except: if gc_was_enabled: gc.enable() raise if self.pid == 0: # Child # In various places on the child side of things, we catch OSError # and add attributes to it that detail where in the process we failed; # like all exceptions until we have exec'd, this exception is pickled # and sent to the parent to raise in the calling process. # The parent uses this to decide how to treat that exception, # adjusting certain information about it as needed. # # Python 3.11.8 --- yes, a minor patch release --- stopped # letting the 'filename' parameter get set in the resulting # exception for many cases. We're not quite interpreting this # the same way the stdlib is, I'm sure, but this makes the stdlib # tests pass. # XXX: Technically we're doing a lot of stuff here that # may not be safe to do before a exec(), depending on the OS. # CPython 3 goes to great lengths to precompute a lot # of this info before the fork and pass it all to C functions that # try hard not to call things like malloc(). (Of course, # CPython 2 pretty much did what we're doing.) try: # Close parent's pipe ends if p2cwrite != -1: os.close(p2cwrite) if c2pread != -1: os.close(c2pread) if errread != -1: os.close(errread) os.close(errpipe_read) # When duping fds, if there arises a situation # where one of the fds is either 0, 1 or 2, it # is possible that it is overwritten (#12607). if c2pwrite == 0: c2pwrite = os.dup(c2pwrite) _set_inheritable(c2pwrite, False) while errwrite in (0, 1): errwrite = os.dup(errwrite) _set_inheritable(errwrite, False) # Dup fds for child def _dup2(existing, desired): # dup2() removes the CLOEXEC flag but # we must do it ourselves if dup2() # would be a no-op (issue #10806). if existing == desired: self._set_cloexec_flag(existing, False) elif existing != -1: os.dup2(existing, desired) try: self._remove_nonblock_flag(desired) except OSError: # Ignore EBADF, it may not actually be # open yet. # Tested beginning in 3.7.0b3 test_subprocess.py pass _dup2(p2cread, 0) _dup2(c2pwrite, 1) _dup2(errwrite, 2) # Close pipe fds. Make sure we don't close the # same fd more than once, or standard fds. if not True: closed = set([None]) for fd in (p2cread, c2pwrite, errwrite): if fd not in closed and fd > 2: os.close(fd) closed.add(fd) # Python 3 (with a working set_inheritable): # We no longer manually close p2cread, # c2pwrite, and errwrite here as # _close_open_fds takes care when it is # not already non-inheritable. if cwd is not None: try: os.chdir(cwd) except OSError as e: e._failed_chdir = True raise # Python 3.9 if umask >= 0: os.umask(umask) # XXX: CPython does _Py_RestoreSignals here. # Then setsid() based on ??? try: if gids: os.setgroups(gids) if gid: os.setregid(gid, gid) if uid: os.setreuid(uid, uid) if process_group is not None: os.setpgid(0, process_group) except OSError as e: e._failed_chuser = True raise if preexec_fn: preexec_fn() # Close all other fds, if asked for. This must be done # after preexec_fn runs. if close_fds: fds_to_keep = set(pass_fds) fds_to_keep.add(errpipe_write) self._close_fds(fds_to_keep, errpipe_write) if restore_signals: # restore the documented signals back to sig_dfl; # not all will be defined on every platform for sig in 'SIGPIPE', 'SIGXFZ', 'SIGXFSZ': sig = getattr(signal, sig, None) if sig is not None: signal.signal(sig, signal.SIG_DFL) if start_new_session: os.setsid() try: if env is None: os.execvp(executable, args) else: # Python 3.6 started testing for # bytes values in the env; it also # started encoding strs using # fsencode and using a lower-level # API that takes a list of keys # and values. We don't have access # to that API, so we go the reverse direction. env = {os.fsdecode(k) if isinstance(k, bytes) else k: os.fsdecode(v) if isinstance(v, bytes) else v for k, v in env.items()} os.execvpe(executable, args, env) except OSError as e: e._failed_exec = True raise except: exc_type, exc_value, tb = sys.exc_info() # Save the traceback and attach it to the exception object exc_lines = traceback.format_exception(exc_type, exc_value, tb) exc_value.child_traceback = ''.join(exc_lines) os.write(errpipe_write, pickle.dumps(exc_value)) finally: # Make sure that the process exits no matter what. # The return code does not matter much as it won't be # reported to the application os._exit(1) # Parent self._child_created = True if gc_was_enabled: gc.enable() finally: # be sure the FD is closed no matter what os.close(errpipe_write) # self._devnull is not always defined. devnull_fd = getattr(self, '_devnull', None) if p2cread != -1 and p2cwrite != -1 and p2cread != devnull_fd: os.close(p2cread) if c2pwrite != -1 and c2pread != -1 and c2pwrite != devnull_fd: os.close(c2pwrite) if errwrite != -1 and errread != -1 and errwrite != devnull_fd: os.close(errwrite) if devnull_fd is not None: os.close(devnull_fd) # Prevent a double close of these fds from __init__ on error. self._closed_child_pipe_fds = True # Wait for exec to fail or succeed; possibly raising exception errpipe_read = FileObject(errpipe_read, 'rb') data = errpipe_read.read() finally: try: if hasattr(errpipe_read, 'close'): errpipe_read.close() else: os.close(errpipe_read) except OSError: # Especially on PyPy, we sometimes see the above # `os.close(errpipe_read)` raise an OSError. # It's not entirely clear why, but it happens in # InterprocessSignalTests.test_main sometimes, which must mean # we have some sort of race condition. pass finally: errpipe_read = -1 if data != b"": self.wait() child_exception = pickle.loads(data) for fd in (p2cwrite, c2pread, errread): if fd is not None and fd != -1: os.close(fd) if isinstance(child_exception, OSError): child_exception.filename = executable if hasattr(child_exception, '_failed_chdir'): child_exception.filename = cwd if getattr(child_exception, '_failed_chuser', False): child_exception.filename = None > raise child_exception E OSError: [Errno 8] Exec format error: 'locust' /usr/lib/python3/dist-packages/gevent/subprocess.py:1838: OSError _________________ DistributedIntegrationTests.test_distributed _________________ self = def test_distributed(self): LOCUSTFILE_CONTENT = textwrap.dedent( """ from locust import User, task, constant class User1(User): wait_time = constant(1) @task def t(self): pass """ ) with mock_locustfile(content=LOCUSTFILE_CONTENT) as mocked: > proc = subprocess.Popen( [ "locust", "-f", mocked.file_path, "--headless", "--master", "--expect-workers", "1", "-u", "3", "-t", "5s", ], stderr=STDOUT, stdout=PIPE, text=True, ) locust/test/test_main.py:1570: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3/dist-packages/gevent/subprocess.py:808: in __init__ self._execute_child(args, executable, preexec_fn, close_fds, _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = args = ['locust', '-f', '/build/reproducible-path/locust-2.24.0/locust/test/mock_locustfile_1715255811_7621796_41577.py', '--headless', '--master', '--expect-workers', ...] executable = 'locust', preexec_fn = None, close_fds = True, pass_fds = () cwd = None, env = None, universal_newlines = None, startupinfo = None creationflags = 0, shell = False, p2cread = -1, p2cwrite = -1, c2pread = 11 c2pwrite = 81, errread = -1, errwrite = 81, restore_signals = True, gid = None gids = None, uid = None, umask = -1, start_new_session = False process_group = None def _execute_child(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, universal_newlines, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, restore_signals, gid, gids, uid, umask, start_new_session, process_group): """Execute program (POSIX version)""" if isinstance(args, (str, bytes)): args = [args] elif isinstance(args, PathLike): if shell: raise TypeError('path-like args is not allowed when ' 'shell is true') args = [fsencode(args)] # os.PathLike -> [str] else: args = list(args) if shell: # On Android the default shell is at '/system/bin/sh'. unix_shell = ( '/system/bin/sh' if hasattr(sys, 'getandroidapilevel') else '/bin/sh' ) args = [unix_shell, "-c"] + args if executable: args[0] = executable if executable is None: executable = args[0] self._loop.install_sigchld() # For transferring possible exec failure from child to parent # The first char specifies the exception type: 0 means # OSError, 1 means some other error. errpipe_read, errpipe_write = self.pipe_cloexec() # errpipe_write must not be in the standard io 0, 1, or 2 fd range. low_fds_to_close = [] while errpipe_write < 3: low_fds_to_close.append(errpipe_write) errpipe_write = os.dup(errpipe_write) for low_fd in low_fds_to_close: os.close(low_fd) try: try: gc_was_enabled = gc.isenabled() # Disable gc to avoid bug where gc -> file_dealloc -> # write to stderr -> hang. http://bugs.python.org/issue1336 gc.disable() try: self.pid = fork_and_watch(self._on_child, self._loop, True, fork) except: if gc_was_enabled: gc.enable() raise if self.pid == 0: # Child # In various places on the child side of things, we catch OSError # and add attributes to it that detail where in the process we failed; # like all exceptions until we have exec'd, this exception is pickled # and sent to the parent to raise in the calling process. # The parent uses this to decide how to treat that exception, # adjusting certain information about it as needed. # # Python 3.11.8 --- yes, a minor patch release --- stopped # letting the 'filename' parameter get set in the resulting # exception for many cases. We're not quite interpreting this # the same way the stdlib is, I'm sure, but this makes the stdlib # tests pass. # XXX: Technically we're doing a lot of stuff here that # may not be safe to do before a exec(), depending on the OS. # CPython 3 goes to great lengths to precompute a lot # of this info before the fork and pass it all to C functions that # try hard not to call things like malloc(). (Of course, # CPython 2 pretty much did what we're doing.) try: # Close parent's pipe ends if p2cwrite != -1: os.close(p2cwrite) if c2pread != -1: os.close(c2pread) if errread != -1: os.close(errread) os.close(errpipe_read) # When duping fds, if there arises a situation # where one of the fds is either 0, 1 or 2, it # is possible that it is overwritten (#12607). if c2pwrite == 0: c2pwrite = os.dup(c2pwrite) _set_inheritable(c2pwrite, False) while errwrite in (0, 1): errwrite = os.dup(errwrite) _set_inheritable(errwrite, False) # Dup fds for child def _dup2(existing, desired): # dup2() removes the CLOEXEC flag but # we must do it ourselves if dup2() # would be a no-op (issue #10806). if existing == desired: self._set_cloexec_flag(existing, False) elif existing != -1: os.dup2(existing, desired) try: self._remove_nonblock_flag(desired) except OSError: # Ignore EBADF, it may not actually be # open yet. # Tested beginning in 3.7.0b3 test_subprocess.py pass _dup2(p2cread, 0) _dup2(c2pwrite, 1) _dup2(errwrite, 2) # Close pipe fds. Make sure we don't close the # same fd more than once, or standard fds. if not True: closed = set([None]) for fd in (p2cread, c2pwrite, errwrite): if fd not in closed and fd > 2: os.close(fd) closed.add(fd) # Python 3 (with a working set_inheritable): # We no longer manually close p2cread, # c2pwrite, and errwrite here as # _close_open_fds takes care when it is # not already non-inheritable. if cwd is not None: try: os.chdir(cwd) except OSError as e: e._failed_chdir = True raise # Python 3.9 if umask >= 0: os.umask(umask) # XXX: CPython does _Py_RestoreSignals here. # Then setsid() based on ??? try: if gids: os.setgroups(gids) if gid: os.setregid(gid, gid) if uid: os.setreuid(uid, uid) if process_group is not None: os.setpgid(0, process_group) except OSError as e: e._failed_chuser = True raise if preexec_fn: preexec_fn() # Close all other fds, if asked for. This must be done # after preexec_fn runs. if close_fds: fds_to_keep = set(pass_fds) fds_to_keep.add(errpipe_write) self._close_fds(fds_to_keep, errpipe_write) if restore_signals: # restore the documented signals back to sig_dfl; # not all will be defined on every platform for sig in 'SIGPIPE', 'SIGXFZ', 'SIGXFSZ': sig = getattr(signal, sig, None) if sig is not None: signal.signal(sig, signal.SIG_DFL) if start_new_session: os.setsid() try: if env is None: os.execvp(executable, args) else: # Python 3.6 started testing for # bytes values in the env; it also # started encoding strs using # fsencode and using a lower-level # API that takes a list of keys # and values. We don't have access # to that API, so we go the reverse direction. env = {os.fsdecode(k) if isinstance(k, bytes) else k: os.fsdecode(v) if isinstance(v, bytes) else v for k, v in env.items()} os.execvpe(executable, args, env) except OSError as e: e._failed_exec = True raise except: exc_type, exc_value, tb = sys.exc_info() # Save the traceback and attach it to the exception object exc_lines = traceback.format_exception(exc_type, exc_value, tb) exc_value.child_traceback = ''.join(exc_lines) os.write(errpipe_write, pickle.dumps(exc_value)) finally: # Make sure that the process exits no matter what. # The return code does not matter much as it won't be # reported to the application os._exit(1) # Parent self._child_created = True if gc_was_enabled: gc.enable() finally: # be sure the FD is closed no matter what os.close(errpipe_write) # self._devnull is not always defined. devnull_fd = getattr(self, '_devnull', None) if p2cread != -1 and p2cwrite != -1 and p2cread != devnull_fd: os.close(p2cread) if c2pwrite != -1 and c2pread != -1 and c2pwrite != devnull_fd: os.close(c2pwrite) if errwrite != -1 and errread != -1 and errwrite != devnull_fd: os.close(errwrite) if devnull_fd is not None: os.close(devnull_fd) # Prevent a double close of these fds from __init__ on error. self._closed_child_pipe_fds = True # Wait for exec to fail or succeed; possibly raising exception errpipe_read = FileObject(errpipe_read, 'rb') data = errpipe_read.read() finally: try: if hasattr(errpipe_read, 'close'): errpipe_read.close() else: os.close(errpipe_read) except OSError: # Especially on PyPy, we sometimes see the above # `os.close(errpipe_read)` raise an OSError. # It's not entirely clear why, but it happens in # InterprocessSignalTests.test_main sometimes, which must mean # we have some sort of race condition. pass finally: errpipe_read = -1 if data != b"": self.wait() child_exception = pickle.loads(data) for fd in (p2cwrite, c2pread, errread): if fd is not None and fd != -1: os.close(fd) if isinstance(child_exception, OSError): child_exception.filename = executable if hasattr(child_exception, '_failed_chdir'): child_exception.filename = cwd if getattr(child_exception, '_failed_chuser', False): child_exception.filename = None > raise child_exception E OSError: [Errno 8] Exec format error: 'locust' /usr/lib/python3/dist-packages/gevent/subprocess.py:1838: OSError _____________ DistributedIntegrationTests.test_distributed_events ______________ self = def test_distributed_events(self): content = ( MOCK_LOCUSTFILE_CONTENT + """ from locust import events from locust.runners import MasterRunner @events.test_start.add_listener def on_test_start(environment, **kwargs): if isinstance(environment.runner, MasterRunner): print("test_start on master") else: print("test_start on worker") @events.test_stop.add_listener def on_test_stop(environment, **kwargs): if isinstance(environment.runner, MasterRunner): print("test_stop on master") else: print("test_stop on worker") """ ) with mock_locustfile(content=content) as mocked: > proc = subprocess.Popen( [ "locust", "-f", mocked.file_path, "--headless", "--master", "--expect-workers", "1", "-t", "1", "--exit-code-on-error", "0", "-L", "DEBUG", ], stdout=PIPE, stderr=PIPE, text=True, ) locust/test/test_main.py:1448: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3/dist-packages/gevent/subprocess.py:808: in __init__ self._execute_child(args, executable, preexec_fn, close_fds, _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = args = ['locust', '-f', '/build/reproducible-path/locust-2.24.0/locust/test/mock_locustfile_1715255811_9581501_57377.py', '--headless', '--master', '--expect-workers', ...] executable = 'locust', preexec_fn = None, close_fds = True, pass_fds = () cwd = None, env = None, universal_newlines = None, startupinfo = None creationflags = 0, shell = False, p2cread = -1, p2cwrite = -1, c2pread = 11 c2pwrite = 81, errread = 82, errwrite = 83, restore_signals = True, gid = None gids = None, uid = None, umask = -1, start_new_session = False process_group = None def _execute_child(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, universal_newlines, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, restore_signals, gid, gids, uid, umask, start_new_session, process_group): """Execute program (POSIX version)""" if isinstance(args, (str, bytes)): args = [args] elif isinstance(args, PathLike): if shell: raise TypeError('path-like args is not allowed when ' 'shell is true') args = [fsencode(args)] # os.PathLike -> [str] else: args = list(args) if shell: # On Android the default shell is at '/system/bin/sh'. unix_shell = ( '/system/bin/sh' if hasattr(sys, 'getandroidapilevel') else '/bin/sh' ) args = [unix_shell, "-c"] + args if executable: args[0] = executable if executable is None: executable = args[0] self._loop.install_sigchld() # For transferring possible exec failure from child to parent # The first char specifies the exception type: 0 means # OSError, 1 means some other error. errpipe_read, errpipe_write = self.pipe_cloexec() # errpipe_write must not be in the standard io 0, 1, or 2 fd range. low_fds_to_close = [] while errpipe_write < 3: low_fds_to_close.append(errpipe_write) errpipe_write = os.dup(errpipe_write) for low_fd in low_fds_to_close: os.close(low_fd) try: try: gc_was_enabled = gc.isenabled() # Disable gc to avoid bug where gc -> file_dealloc -> # write to stderr -> hang. http://bugs.python.org/issue1336 gc.disable() try: self.pid = fork_and_watch(self._on_child, self._loop, True, fork) except: if gc_was_enabled: gc.enable() raise if self.pid == 0: # Child # In various places on the child side of things, we catch OSError # and add attributes to it that detail where in the process we failed; # like all exceptions until we have exec'd, this exception is pickled # and sent to the parent to raise in the calling process. # The parent uses this to decide how to treat that exception, # adjusting certain information about it as needed. # # Python 3.11.8 --- yes, a minor patch release --- stopped # letting the 'filename' parameter get set in the resulting # exception for many cases. We're not quite interpreting this # the same way the stdlib is, I'm sure, but this makes the stdlib # tests pass. # XXX: Technically we're doing a lot of stuff here that # may not be safe to do before a exec(), depending on the OS. # CPython 3 goes to great lengths to precompute a lot # of this info before the fork and pass it all to C functions that # try hard not to call things like malloc(). (Of course, # CPython 2 pretty much did what we're doing.) try: # Close parent's pipe ends if p2cwrite != -1: os.close(p2cwrite) if c2pread != -1: os.close(c2pread) if errread != -1: os.close(errread) os.close(errpipe_read) # When duping fds, if there arises a situation # where one of the fds is either 0, 1 or 2, it # is possible that it is overwritten (#12607). if c2pwrite == 0: c2pwrite = os.dup(c2pwrite) _set_inheritable(c2pwrite, False) while errwrite in (0, 1): errwrite = os.dup(errwrite) _set_inheritable(errwrite, False) # Dup fds for child def _dup2(existing, desired): # dup2() removes the CLOEXEC flag but # we must do it ourselves if dup2() # would be a no-op (issue #10806). if existing == desired: self._set_cloexec_flag(existing, False) elif existing != -1: os.dup2(existing, desired) try: self._remove_nonblock_flag(desired) except OSError: # Ignore EBADF, it may not actually be # open yet. # Tested beginning in 3.7.0b3 test_subprocess.py pass _dup2(p2cread, 0) _dup2(c2pwrite, 1) _dup2(errwrite, 2) # Close pipe fds. Make sure we don't close the # same fd more than once, or standard fds. if not True: closed = set([None]) for fd in (p2cread, c2pwrite, errwrite): if fd not in closed and fd > 2: os.close(fd) closed.add(fd) # Python 3 (with a working set_inheritable): # We no longer manually close p2cread, # c2pwrite, and errwrite here as # _close_open_fds takes care when it is # not already non-inheritable. if cwd is not None: try: os.chdir(cwd) except OSError as e: e._failed_chdir = True raise # Python 3.9 if umask >= 0: os.umask(umask) # XXX: CPython does _Py_RestoreSignals here. # Then setsid() based on ??? try: if gids: os.setgroups(gids) if gid: os.setregid(gid, gid) if uid: os.setreuid(uid, uid) if process_group is not None: os.setpgid(0, process_group) except OSError as e: e._failed_chuser = True raise if preexec_fn: preexec_fn() # Close all other fds, if asked for. This must be done # after preexec_fn runs. if close_fds: fds_to_keep = set(pass_fds) fds_to_keep.add(errpipe_write) self._close_fds(fds_to_keep, errpipe_write) if restore_signals: # restore the documented signals back to sig_dfl; # not all will be defined on every platform for sig in 'SIGPIPE', 'SIGXFZ', 'SIGXFSZ': sig = getattr(signal, sig, None) if sig is not None: signal.signal(sig, signal.SIG_DFL) if start_new_session: os.setsid() try: if env is None: os.execvp(executable, args) else: # Python 3.6 started testing for # bytes values in the env; it also # started encoding strs using # fsencode and using a lower-level # API that takes a list of keys # and values. We don't have access # to that API, so we go the reverse direction. env = {os.fsdecode(k) if isinstance(k, bytes) else k: os.fsdecode(v) if isinstance(v, bytes) else v for k, v in env.items()} os.execvpe(executable, args, env) except OSError as e: e._failed_exec = True raise except: exc_type, exc_value, tb = sys.exc_info() # Save the traceback and attach it to the exception object exc_lines = traceback.format_exception(exc_type, exc_value, tb) exc_value.child_traceback = ''.join(exc_lines) os.write(errpipe_write, pickle.dumps(exc_value)) finally: # Make sure that the process exits no matter what. # The return code does not matter much as it won't be # reported to the application os._exit(1) # Parent self._child_created = True if gc_was_enabled: gc.enable() finally: # be sure the FD is closed no matter what os.close(errpipe_write) # self._devnull is not always defined. devnull_fd = getattr(self, '_devnull', None) if p2cread != -1 and p2cwrite != -1 and p2cread != devnull_fd: os.close(p2cread) if c2pwrite != -1 and c2pread != -1 and c2pwrite != devnull_fd: os.close(c2pwrite) if errwrite != -1 and errread != -1 and errwrite != devnull_fd: os.close(errwrite) if devnull_fd is not None: os.close(devnull_fd) # Prevent a double close of these fds from __init__ on error. self._closed_child_pipe_fds = True # Wait for exec to fail or succeed; possibly raising exception errpipe_read = FileObject(errpipe_read, 'rb') data = errpipe_read.read() finally: try: if hasattr(errpipe_read, 'close'): errpipe_read.close() else: os.close(errpipe_read) except OSError: # Especially on PyPy, we sometimes see the above # `os.close(errpipe_read)` raise an OSError. # It's not entirely clear why, but it happens in # InterprocessSignalTests.test_main sometimes, which must mean # we have some sort of race condition. pass finally: errpipe_read = -1 if data != b"": self.wait() child_exception = pickle.loads(data) for fd in (p2cwrite, c2pread, errread): if fd is not None and fd != -1: os.close(fd) if isinstance(child_exception, OSError): child_exception.filename = executable if hasattr(child_exception, '_failed_chdir'): child_exception.filename = cwd if getattr(child_exception, '_failed_chuser', False): child_exception.filename = None > raise child_exception E OSError: [Errno 8] Exec format error: 'locust' /usr/lib/python3/dist-packages/gevent/subprocess.py:1838: OSError _____ DistributedIntegrationTests.test_distributed_report_timeout_expired ______ self = def test_distributed_report_timeout_expired(self): LOCUSTFILE_CONTENT = textwrap.dedent( """ from locust import User, task, constant class User1(User): wait_time = constant(1) @task def t(self): pass """ ) with mock_locustfile(content=LOCUSTFILE_CONTENT) as mocked, patch_env( "LOCUST_WAIT_FOR_WORKERS_REPORT_AFTER_RAMP_UP", "0.01" ) as _: > proc = subprocess.Popen( [ "locust", "-f", mocked.file_path, "--headless", "--master", "--expect-workers", "1", "-u", "3", "-t", "5s", ], stderr=STDOUT, stdout=PIPE, text=True, ) locust/test/test_main.py:1624: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3/dist-packages/gevent/subprocess.py:808: in __init__ self._execute_child(args, executable, preexec_fn, close_fds, _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = args = ['locust', '-f', '/build/reproducible-path/locust-2.24.0/locust/test/mock_locustfile_1715255812_1461625_22661.py', '--headless', '--master', '--expect-workers', ...] executable = 'locust', preexec_fn = None, close_fds = True, pass_fds = () cwd = None, env = None, universal_newlines = None, startupinfo = None creationflags = 0, shell = False, p2cread = -1, p2cwrite = -1, c2pread = 11 c2pwrite = 81, errread = -1, errwrite = 81, restore_signals = True, gid = None gids = None, uid = None, umask = -1, start_new_session = False process_group = None def _execute_child(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, universal_newlines, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, restore_signals, gid, gids, uid, umask, start_new_session, process_group): """Execute program (POSIX version)""" if isinstance(args, (str, bytes)): args = [args] elif isinstance(args, PathLike): if shell: raise TypeError('path-like args is not allowed when ' 'shell is true') args = [fsencode(args)] # os.PathLike -> [str] else: args = list(args) if shell: # On Android the default shell is at '/system/bin/sh'. unix_shell = ( '/system/bin/sh' if hasattr(sys, 'getandroidapilevel') else '/bin/sh' ) args = [unix_shell, "-c"] + args if executable: args[0] = executable if executable is None: executable = args[0] self._loop.install_sigchld() # For transferring possible exec failure from child to parent # The first char specifies the exception type: 0 means # OSError, 1 means some other error. errpipe_read, errpipe_write = self.pipe_cloexec() # errpipe_write must not be in the standard io 0, 1, or 2 fd range. low_fds_to_close = [] while errpipe_write < 3: low_fds_to_close.append(errpipe_write) errpipe_write = os.dup(errpipe_write) for low_fd in low_fds_to_close: os.close(low_fd) try: try: gc_was_enabled = gc.isenabled() # Disable gc to avoid bug where gc -> file_dealloc -> # write to stderr -> hang. http://bugs.python.org/issue1336 gc.disable() try: self.pid = fork_and_watch(self._on_child, self._loop, True, fork) except: if gc_was_enabled: gc.enable() raise if self.pid == 0: # Child # In various places on the child side of things, we catch OSError # and add attributes to it that detail where in the process we failed; # like all exceptions until we have exec'd, this exception is pickled # and sent to the parent to raise in the calling process. # The parent uses this to decide how to treat that exception, # adjusting certain information about it as needed. # # Python 3.11.8 --- yes, a minor patch release --- stopped # letting the 'filename' parameter get set in the resulting # exception for many cases. We're not quite interpreting this # the same way the stdlib is, I'm sure, but this makes the stdlib # tests pass. # XXX: Technically we're doing a lot of stuff here that # may not be safe to do before a exec(), depending on the OS. # CPython 3 goes to great lengths to precompute a lot # of this info before the fork and pass it all to C functions that # try hard not to call things like malloc(). (Of course, # CPython 2 pretty much did what we're doing.) try: # Close parent's pipe ends if p2cwrite != -1: os.close(p2cwrite) if c2pread != -1: os.close(c2pread) if errread != -1: os.close(errread) os.close(errpipe_read) # When duping fds, if there arises a situation # where one of the fds is either 0, 1 or 2, it # is possible that it is overwritten (#12607). if c2pwrite == 0: c2pwrite = os.dup(c2pwrite) _set_inheritable(c2pwrite, False) while errwrite in (0, 1): errwrite = os.dup(errwrite) _set_inheritable(errwrite, False) # Dup fds for child def _dup2(existing, desired): # dup2() removes the CLOEXEC flag but # we must do it ourselves if dup2() # would be a no-op (issue #10806). if existing == desired: self._set_cloexec_flag(existing, False) elif existing != -1: os.dup2(existing, desired) try: self._remove_nonblock_flag(desired) except OSError: # Ignore EBADF, it may not actually be # open yet. # Tested beginning in 3.7.0b3 test_subprocess.py pass _dup2(p2cread, 0) _dup2(c2pwrite, 1) _dup2(errwrite, 2) # Close pipe fds. Make sure we don't close the # same fd more than once, or standard fds. if not True: closed = set([None]) for fd in (p2cread, c2pwrite, errwrite): if fd not in closed and fd > 2: os.close(fd) closed.add(fd) # Python 3 (with a working set_inheritable): # We no longer manually close p2cread, # c2pwrite, and errwrite here as # _close_open_fds takes care when it is # not already non-inheritable. if cwd is not None: try: os.chdir(cwd) except OSError as e: e._failed_chdir = True raise # Python 3.9 if umask >= 0: os.umask(umask) # XXX: CPython does _Py_RestoreSignals here. # Then setsid() based on ??? try: if gids: os.setgroups(gids) if gid: os.setregid(gid, gid) if uid: os.setreuid(uid, uid) if process_group is not None: os.setpgid(0, process_group) except OSError as e: e._failed_chuser = True raise if preexec_fn: preexec_fn() # Close all other fds, if asked for. This must be done # after preexec_fn runs. if close_fds: fds_to_keep = set(pass_fds) fds_to_keep.add(errpipe_write) self._close_fds(fds_to_keep, errpipe_write) if restore_signals: # restore the documented signals back to sig_dfl; # not all will be defined on every platform for sig in 'SIGPIPE', 'SIGXFZ', 'SIGXFSZ': sig = getattr(signal, sig, None) if sig is not None: signal.signal(sig, signal.SIG_DFL) if start_new_session: os.setsid() try: if env is None: os.execvp(executable, args) else: # Python 3.6 started testing for # bytes values in the env; it also # started encoding strs using # fsencode and using a lower-level # API that takes a list of keys # and values. We don't have access # to that API, so we go the reverse direction. env = {os.fsdecode(k) if isinstance(k, bytes) else k: os.fsdecode(v) if isinstance(v, bytes) else v for k, v in env.items()} os.execvpe(executable, args, env) except OSError as e: e._failed_exec = True raise except: exc_type, exc_value, tb = sys.exc_info() # Save the traceback and attach it to the exception object exc_lines = traceback.format_exception(exc_type, exc_value, tb) exc_value.child_traceback = ''.join(exc_lines) os.write(errpipe_write, pickle.dumps(exc_value)) finally: # Make sure that the process exits no matter what. # The return code does not matter much as it won't be # reported to the application os._exit(1) # Parent self._child_created = True if gc_was_enabled: gc.enable() finally: # be sure the FD is closed no matter what os.close(errpipe_write) # self._devnull is not always defined. devnull_fd = getattr(self, '_devnull', None) if p2cread != -1 and p2cwrite != -1 and p2cread != devnull_fd: os.close(p2cread) if c2pwrite != -1 and c2pread != -1 and c2pwrite != devnull_fd: os.close(c2pwrite) if errwrite != -1 and errread != -1 and errwrite != devnull_fd: os.close(errwrite) if devnull_fd is not None: os.close(devnull_fd) # Prevent a double close of these fds from __init__ on error. self._closed_child_pipe_fds = True # Wait for exec to fail or succeed; possibly raising exception errpipe_read = FileObject(errpipe_read, 'rb') data = errpipe_read.read() finally: try: if hasattr(errpipe_read, 'close'): errpipe_read.close() else: os.close(errpipe_read) except OSError: # Especially on PyPy, we sometimes see the above # `os.close(errpipe_read)` raise an OSError. # It's not entirely clear why, but it happens in # InterprocessSignalTests.test_main sometimes, which must mean # we have some sort of race condition. pass finally: errpipe_read = -1 if data != b"": self.wait() child_exception = pickle.loads(data) for fd in (p2cwrite, c2pread, errread): if fd is not None and fd != -1: os.close(fd) if isinstance(child_exception, OSError): child_exception.filename = executable if hasattr(child_exception, '_failed_chdir'): child_exception.filename = cwd if getattr(child_exception, '_failed_chuser', False): child_exception.filename = None > raise child_exception E OSError: [Errno 8] Exec format error: 'locust' /usr/lib/python3/dist-packages/gevent/subprocess.py:1838: OSError ______________ DistributedIntegrationTests.test_distributed_tags _______________ self = def test_distributed_tags(self): content = """ from locust import HttpUser, TaskSet, task, between, LoadTestShape, tag class SecondUser(HttpUser): host = "http://127.0.0.1:8089" wait_time = between(0, 0.1) @tag("tag1") @task def task1(self): print("task1") @tag("tag2") @task def task2(self): print("task2") """ with mock_locustfile(content=content) as mocked: > proc = subprocess.Popen( [ "locust", "-f", mocked.file_path, "--headless", "--master", "--expect-workers", "1", "-t", "1", "-u", "2", "--exit-code-on-error", "0", "-L", "DEBUG", "--tags", "tag1", ], stdout=PIPE, stderr=PIPE, text=True, ) locust/test/test_main.py:1509: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3/dist-packages/gevent/subprocess.py:808: in __init__ self._execute_child(args, executable, preexec_fn, close_fds, _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = args = ['locust', '-f', '/build/reproducible-path/locust-2.24.0/locust/test/mock_locustfile_1715255812_3375504_82088.py', '--headless', '--master', '--expect-workers', ...] executable = 'locust', preexec_fn = None, close_fds = True, pass_fds = () cwd = None, env = None, universal_newlines = None, startupinfo = None creationflags = 0, shell = False, p2cread = -1, p2cwrite = -1, c2pread = 11 c2pwrite = 81, errread = 82, errwrite = 83, restore_signals = True, gid = None gids = None, uid = None, umask = -1, start_new_session = False process_group = None def _execute_child(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, universal_newlines, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, restore_signals, gid, gids, uid, umask, start_new_session, process_group): """Execute program (POSIX version)""" if isinstance(args, (str, bytes)): args = [args] elif isinstance(args, PathLike): if shell: raise TypeError('path-like args is not allowed when ' 'shell is true') args = [fsencode(args)] # os.PathLike -> [str] else: args = list(args) if shell: # On Android the default shell is at '/system/bin/sh'. unix_shell = ( '/system/bin/sh' if hasattr(sys, 'getandroidapilevel') else '/bin/sh' ) args = [unix_shell, "-c"] + args if executable: args[0] = executable if executable is None: executable = args[0] self._loop.install_sigchld() # For transferring possible exec failure from child to parent # The first char specifies the exception type: 0 means # OSError, 1 means some other error. errpipe_read, errpipe_write = self.pipe_cloexec() # errpipe_write must not be in the standard io 0, 1, or 2 fd range. low_fds_to_close = [] while errpipe_write < 3: low_fds_to_close.append(errpipe_write) errpipe_write = os.dup(errpipe_write) for low_fd in low_fds_to_close: os.close(low_fd) try: try: gc_was_enabled = gc.isenabled() # Disable gc to avoid bug where gc -> file_dealloc -> # write to stderr -> hang. http://bugs.python.org/issue1336 gc.disable() try: self.pid = fork_and_watch(self._on_child, self._loop, True, fork) except: if gc_was_enabled: gc.enable() raise if self.pid == 0: # Child # In various places on the child side of things, we catch OSError # and add attributes to it that detail where in the process we failed; # like all exceptions until we have exec'd, this exception is pickled # and sent to the parent to raise in the calling process. # The parent uses this to decide how to treat that exception, # adjusting certain information about it as needed. # # Python 3.11.8 --- yes, a minor patch release --- stopped # letting the 'filename' parameter get set in the resulting # exception for many cases. We're not quite interpreting this # the same way the stdlib is, I'm sure, but this makes the stdlib # tests pass. # XXX: Technically we're doing a lot of stuff here that # may not be safe to do before a exec(), depending on the OS. # CPython 3 goes to great lengths to precompute a lot # of this info before the fork and pass it all to C functions that # try hard not to call things like malloc(). (Of course, # CPython 2 pretty much did what we're doing.) try: # Close parent's pipe ends if p2cwrite != -1: os.close(p2cwrite) if c2pread != -1: os.close(c2pread) if errread != -1: os.close(errread) os.close(errpipe_read) # When duping fds, if there arises a situation # where one of the fds is either 0, 1 or 2, it # is possible that it is overwritten (#12607). if c2pwrite == 0: c2pwrite = os.dup(c2pwrite) _set_inheritable(c2pwrite, False) while errwrite in (0, 1): errwrite = os.dup(errwrite) _set_inheritable(errwrite, False) # Dup fds for child def _dup2(existing, desired): # dup2() removes the CLOEXEC flag but # we must do it ourselves if dup2() # would be a no-op (issue #10806). if existing == desired: self._set_cloexec_flag(existing, False) elif existing != -1: os.dup2(existing, desired) try: self._remove_nonblock_flag(desired) except OSError: # Ignore EBADF, it may not actually be # open yet. # Tested beginning in 3.7.0b3 test_subprocess.py pass _dup2(p2cread, 0) _dup2(c2pwrite, 1) _dup2(errwrite, 2) # Close pipe fds. Make sure we don't close the # same fd more than once, or standard fds. if not True: closed = set([None]) for fd in (p2cread, c2pwrite, errwrite): if fd not in closed and fd > 2: os.close(fd) closed.add(fd) # Python 3 (with a working set_inheritable): # We no longer manually close p2cread, # c2pwrite, and errwrite here as # _close_open_fds takes care when it is # not already non-inheritable. if cwd is not None: try: os.chdir(cwd) except OSError as e: e._failed_chdir = True raise # Python 3.9 if umask >= 0: os.umask(umask) # XXX: CPython does _Py_RestoreSignals here. # Then setsid() based on ??? try: if gids: os.setgroups(gids) if gid: os.setregid(gid, gid) if uid: os.setreuid(uid, uid) if process_group is not None: os.setpgid(0, process_group) except OSError as e: e._failed_chuser = True raise if preexec_fn: preexec_fn() # Close all other fds, if asked for. This must be done # after preexec_fn runs. if close_fds: fds_to_keep = set(pass_fds) fds_to_keep.add(errpipe_write) self._close_fds(fds_to_keep, errpipe_write) if restore_signals: # restore the documented signals back to sig_dfl; # not all will be defined on every platform for sig in 'SIGPIPE', 'SIGXFZ', 'SIGXFSZ': sig = getattr(signal, sig, None) if sig is not None: signal.signal(sig, signal.SIG_DFL) if start_new_session: os.setsid() try: if env is None: os.execvp(executable, args) else: # Python 3.6 started testing for # bytes values in the env; it also # started encoding strs using # fsencode and using a lower-level # API that takes a list of keys # and values. We don't have access # to that API, so we go the reverse direction. env = {os.fsdecode(k) if isinstance(k, bytes) else k: os.fsdecode(v) if isinstance(v, bytes) else v for k, v in env.items()} os.execvpe(executable, args, env) except OSError as e: e._failed_exec = True raise except: exc_type, exc_value, tb = sys.exc_info() # Save the traceback and attach it to the exception object exc_lines = traceback.format_exception(exc_type, exc_value, tb) exc_value.child_traceback = ''.join(exc_lines) os.write(errpipe_write, pickle.dumps(exc_value)) finally: # Make sure that the process exits no matter what. # The return code does not matter much as it won't be # reported to the application os._exit(1) # Parent self._child_created = True if gc_was_enabled: gc.enable() finally: # be sure the FD is closed no matter what os.close(errpipe_write) # self._devnull is not always defined. devnull_fd = getattr(self, '_devnull', None) if p2cread != -1 and p2cwrite != -1 and p2cread != devnull_fd: os.close(p2cread) if c2pwrite != -1 and c2pread != -1 and c2pwrite != devnull_fd: os.close(c2pwrite) if errwrite != -1 and errread != -1 and errwrite != devnull_fd: os.close(errwrite) if devnull_fd is not None: os.close(devnull_fd) # Prevent a double close of these fds from __init__ on error. self._closed_child_pipe_fds = True # Wait for exec to fail or succeed; possibly raising exception errpipe_read = FileObject(errpipe_read, 'rb') data = errpipe_read.read() finally: try: if hasattr(errpipe_read, 'close'): errpipe_read.close() else: os.close(errpipe_read) except OSError: # Especially on PyPy, we sometimes see the above # `os.close(errpipe_read)` raise an OSError. # It's not entirely clear why, but it happens in # InterprocessSignalTests.test_main sometimes, which must mean # we have some sort of race condition. pass finally: errpipe_read = -1 if data != b"": self.wait() child_exception = pickle.loads(data) for fd in (p2cwrite, c2pread, errread): if fd is not None and fd != -1: os.close(fd) if isinstance(child_exception, OSError): child_exception.filename = executable if hasattr(child_exception, '_failed_chdir'): child_exception.filename = cwd if getattr(child_exception, '_failed_chuser', False): child_exception.filename = None > raise child_exception E OSError: [Errno 8] Exec format error: 'locust' /usr/lib/python3/dist-packages/gevent/subprocess.py:1838: OSError _ DistributedIntegrationTests.test_distributed_with_locustfile_distribution_not_plain_filename _ self = def test_distributed_with_locustfile_distribution_not_plain_filename(self): LOCUSTFILE_CONTENT = textwrap.dedent( """ from locust import User, task, constant class User1(User): wait_time = constant(1) @task def t(self): pass """ ) with mock_locustfile(content=LOCUSTFILE_CONTENT) as mocked: > proc = subprocess.Popen( [ "locust", "-f", mocked.file_path[:-3], # remove ".py" "--headless", "--master", ], stderr=STDOUT, stdout=PIPE, text=True, ) locust/test/test_main.py:1804: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3/dist-packages/gevent/subprocess.py:808: in __init__ self._execute_child(args, executable, preexec_fn, close_fds, _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = args = ['locust', '-f', '/build/reproducible-path/locust-2.24.0/locust/test/mock_locustfile_1715255812_5461626_4534', '--headless', '--master'] executable = 'locust', preexec_fn = None, close_fds = True, pass_fds = () cwd = None, env = None, universal_newlines = None, startupinfo = None creationflags = 0, shell = False, p2cread = -1, p2cwrite = -1, c2pread = 11 c2pwrite = 81, errread = -1, errwrite = 81, restore_signals = True, gid = None gids = None, uid = None, umask = -1, start_new_session = False process_group = None def _execute_child(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, universal_newlines, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, restore_signals, gid, gids, uid, umask, start_new_session, process_group): """Execute program (POSIX version)""" if isinstance(args, (str, bytes)): args = [args] elif isinstance(args, PathLike): if shell: raise TypeError('path-like args is not allowed when ' 'shell is true') args = [fsencode(args)] # os.PathLike -> [str] else: args = list(args) if shell: # On Android the default shell is at '/system/bin/sh'. unix_shell = ( '/system/bin/sh' if hasattr(sys, 'getandroidapilevel') else '/bin/sh' ) args = [unix_shell, "-c"] + args if executable: args[0] = executable if executable is None: executable = args[0] self._loop.install_sigchld() # For transferring possible exec failure from child to parent # The first char specifies the exception type: 0 means # OSError, 1 means some other error. errpipe_read, errpipe_write = self.pipe_cloexec() # errpipe_write must not be in the standard io 0, 1, or 2 fd range. low_fds_to_close = [] while errpipe_write < 3: low_fds_to_close.append(errpipe_write) errpipe_write = os.dup(errpipe_write) for low_fd in low_fds_to_close: os.close(low_fd) try: try: gc_was_enabled = gc.isenabled() # Disable gc to avoid bug where gc -> file_dealloc -> # write to stderr -> hang. http://bugs.python.org/issue1336 gc.disable() try: self.pid = fork_and_watch(self._on_child, self._loop, True, fork) except: if gc_was_enabled: gc.enable() raise if self.pid == 0: # Child # In various places on the child side of things, we catch OSError # and add attributes to it that detail where in the process we failed; # like all exceptions until we have exec'd, this exception is pickled # and sent to the parent to raise in the calling process. # The parent uses this to decide how to treat that exception, # adjusting certain information about it as needed. # # Python 3.11.8 --- yes, a minor patch release --- stopped # letting the 'filename' parameter get set in the resulting # exception for many cases. We're not quite interpreting this # the same way the stdlib is, I'm sure, but this makes the stdlib # tests pass. # XXX: Technically we're doing a lot of stuff here that # may not be safe to do before a exec(), depending on the OS. # CPython 3 goes to great lengths to precompute a lot # of this info before the fork and pass it all to C functions that # try hard not to call things like malloc(). (Of course, # CPython 2 pretty much did what we're doing.) try: # Close parent's pipe ends if p2cwrite != -1: os.close(p2cwrite) if c2pread != -1: os.close(c2pread) if errread != -1: os.close(errread) os.close(errpipe_read) # When duping fds, if there arises a situation # where one of the fds is either 0, 1 or 2, it # is possible that it is overwritten (#12607). if c2pwrite == 0: c2pwrite = os.dup(c2pwrite) _set_inheritable(c2pwrite, False) while errwrite in (0, 1): errwrite = os.dup(errwrite) _set_inheritable(errwrite, False) # Dup fds for child def _dup2(existing, desired): # dup2() removes the CLOEXEC flag but # we must do it ourselves if dup2() # would be a no-op (issue #10806). if existing == desired: self._set_cloexec_flag(existing, False) elif existing != -1: os.dup2(existing, desired) try: self._remove_nonblock_flag(desired) except OSError: # Ignore EBADF, it may not actually be # open yet. # Tested beginning in 3.7.0b3 test_subprocess.py pass _dup2(p2cread, 0) _dup2(c2pwrite, 1) _dup2(errwrite, 2) # Close pipe fds. Make sure we don't close the # same fd more than once, or standard fds. if not True: closed = set([None]) for fd in (p2cread, c2pwrite, errwrite): if fd not in closed and fd > 2: os.close(fd) closed.add(fd) # Python 3 (with a working set_inheritable): # We no longer manually close p2cread, # c2pwrite, and errwrite here as # _close_open_fds takes care when it is # not already non-inheritable. if cwd is not None: try: os.chdir(cwd) except OSError as e: e._failed_chdir = True raise # Python 3.9 if umask >= 0: os.umask(umask) # XXX: CPython does _Py_RestoreSignals here. # Then setsid() based on ??? try: if gids: os.setgroups(gids) if gid: os.setregid(gid, gid) if uid: os.setreuid(uid, uid) if process_group is not None: os.setpgid(0, process_group) except OSError as e: e._failed_chuser = True raise if preexec_fn: preexec_fn() # Close all other fds, if asked for. This must be done # after preexec_fn runs. if close_fds: fds_to_keep = set(pass_fds) fds_to_keep.add(errpipe_write) self._close_fds(fds_to_keep, errpipe_write) if restore_signals: # restore the documented signals back to sig_dfl; # not all will be defined on every platform for sig in 'SIGPIPE', 'SIGXFZ', 'SIGXFSZ': sig = getattr(signal, sig, None) if sig is not None: signal.signal(sig, signal.SIG_DFL) if start_new_session: os.setsid() try: if env is None: os.execvp(executable, args) else: # Python 3.6 started testing for # bytes values in the env; it also # started encoding strs using # fsencode and using a lower-level # API that takes a list of keys # and values. We don't have access # to that API, so we go the reverse direction. env = {os.fsdecode(k) if isinstance(k, bytes) else k: os.fsdecode(v) if isinstance(v, bytes) else v for k, v in env.items()} os.execvpe(executable, args, env) except OSError as e: e._failed_exec = True raise except: exc_type, exc_value, tb = sys.exc_info() # Save the traceback and attach it to the exception object exc_lines = traceback.format_exception(exc_type, exc_value, tb) exc_value.child_traceback = ''.join(exc_lines) os.write(errpipe_write, pickle.dumps(exc_value)) finally: # Make sure that the process exits no matter what. # The return code does not matter much as it won't be # reported to the application os._exit(1) # Parent self._child_created = True if gc_was_enabled: gc.enable() finally: # be sure the FD is closed no matter what os.close(errpipe_write) # self._devnull is not always defined. devnull_fd = getattr(self, '_devnull', None) if p2cread != -1 and p2cwrite != -1 and p2cread != devnull_fd: os.close(p2cread) if c2pwrite != -1 and c2pread != -1 and c2pwrite != devnull_fd: os.close(c2pwrite) if errwrite != -1 and errread != -1 and errwrite != devnull_fd: os.close(errwrite) if devnull_fd is not None: os.close(devnull_fd) # Prevent a double close of these fds from __init__ on error. self._closed_child_pipe_fds = True # Wait for exec to fail or succeed; possibly raising exception errpipe_read = FileObject(errpipe_read, 'rb') data = errpipe_read.read() finally: try: if hasattr(errpipe_read, 'close'): errpipe_read.close() else: os.close(errpipe_read) except OSError: # Especially on PyPy, we sometimes see the above # `os.close(errpipe_read)` raise an OSError. # It's not entirely clear why, but it happens in # InterprocessSignalTests.test_main sometimes, which must mean # we have some sort of race condition. pass finally: errpipe_read = -1 if data != b"": self.wait() child_exception = pickle.loads(data) for fd in (p2cwrite, c2pread, errread): if fd is not None and fd != -1: os.close(fd) if isinstance(child_exception, OSError): child_exception.filename = executable if hasattr(child_exception, '_failed_chdir'): child_exception.filename = cwd if getattr(child_exception, '_failed_chuser', False): child_exception.filename = None > raise child_exception E OSError: [Errno 8] Exec format error: 'locust' /usr/lib/python3/dist-packages/gevent/subprocess.py:1838: OSError _______________ DistributedIntegrationTests.test_expect_workers ________________ self = def test_expect_workers(self): with mock_locustfile() as mocked: > proc = subprocess.Popen( [ "locust", "-f", mocked.file_path, "--headless", "--master", "--expect-workers", "2", "--expect-workers-max-wait", "1", ], stdout=PIPE, stderr=PIPE, text=True, ) locust/test/test_main.py:1404: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3/dist-packages/gevent/subprocess.py:808: in __init__ self._execute_child(args, executable, preexec_fn, close_fds, _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = args = ['locust', '-f', '/build/reproducible-path/locust-2.24.0/locust/test/mock_locustfile_1715255812_7605436_34056.py', '--headless', '--master', '--expect-workers', ...] executable = 'locust', preexec_fn = None, close_fds = True, pass_fds = () cwd = None, env = None, universal_newlines = None, startupinfo = None creationflags = 0, shell = False, p2cread = -1, p2cwrite = -1, c2pread = 11 c2pwrite = 81, errread = 82, errwrite = 83, restore_signals = True, gid = None gids = None, uid = None, umask = -1, start_new_session = False process_group = None def _execute_child(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, universal_newlines, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, restore_signals, gid, gids, uid, umask, start_new_session, process_group): """Execute program (POSIX version)""" if isinstance(args, (str, bytes)): args = [args] elif isinstance(args, PathLike): if shell: raise TypeError('path-like args is not allowed when ' 'shell is true') args = [fsencode(args)] # os.PathLike -> [str] else: args = list(args) if shell: # On Android the default shell is at '/system/bin/sh'. unix_shell = ( '/system/bin/sh' if hasattr(sys, 'getandroidapilevel') else '/bin/sh' ) args = [unix_shell, "-c"] + args if executable: args[0] = executable if executable is None: executable = args[0] self._loop.install_sigchld() # For transferring possible exec failure from child to parent # The first char specifies the exception type: 0 means # OSError, 1 means some other error. errpipe_read, errpipe_write = self.pipe_cloexec() # errpipe_write must not be in the standard io 0, 1, or 2 fd range. low_fds_to_close = [] while errpipe_write < 3: low_fds_to_close.append(errpipe_write) errpipe_write = os.dup(errpipe_write) for low_fd in low_fds_to_close: os.close(low_fd) try: try: gc_was_enabled = gc.isenabled() # Disable gc to avoid bug where gc -> file_dealloc -> # write to stderr -> hang. http://bugs.python.org/issue1336 gc.disable() try: self.pid = fork_and_watch(self._on_child, self._loop, True, fork) except: if gc_was_enabled: gc.enable() raise if self.pid == 0: # Child # In various places on the child side of things, we catch OSError # and add attributes to it that detail where in the process we failed; # like all exceptions until we have exec'd, this exception is pickled # and sent to the parent to raise in the calling process. # The parent uses this to decide how to treat that exception, # adjusting certain information about it as needed. # # Python 3.11.8 --- yes, a minor patch release --- stopped # letting the 'filename' parameter get set in the resulting # exception for many cases. We're not quite interpreting this # the same way the stdlib is, I'm sure, but this makes the stdlib # tests pass. # XXX: Technically we're doing a lot of stuff here that # may not be safe to do before a exec(), depending on the OS. # CPython 3 goes to great lengths to precompute a lot # of this info before the fork and pass it all to C functions that # try hard not to call things like malloc(). (Of course, # CPython 2 pretty much did what we're doing.) try: # Close parent's pipe ends if p2cwrite != -1: os.close(p2cwrite) if c2pread != -1: os.close(c2pread) if errread != -1: os.close(errread) os.close(errpipe_read) # When duping fds, if there arises a situation # where one of the fds is either 0, 1 or 2, it # is possible that it is overwritten (#12607). if c2pwrite == 0: c2pwrite = os.dup(c2pwrite) _set_inheritable(c2pwrite, False) while errwrite in (0, 1): errwrite = os.dup(errwrite) _set_inheritable(errwrite, False) # Dup fds for child def _dup2(existing, desired): # dup2() removes the CLOEXEC flag but # we must do it ourselves if dup2() # would be a no-op (issue #10806). if existing == desired: self._set_cloexec_flag(existing, False) elif existing != -1: os.dup2(existing, desired) try: self._remove_nonblock_flag(desired) except OSError: # Ignore EBADF, it may not actually be # open yet. # Tested beginning in 3.7.0b3 test_subprocess.py pass _dup2(p2cread, 0) _dup2(c2pwrite, 1) _dup2(errwrite, 2) # Close pipe fds. Make sure we don't close the # same fd more than once, or standard fds. if not True: closed = set([None]) for fd in (p2cread, c2pwrite, errwrite): if fd not in closed and fd > 2: os.close(fd) closed.add(fd) # Python 3 (with a working set_inheritable): # We no longer manually close p2cread, # c2pwrite, and errwrite here as # _close_open_fds takes care when it is # not already non-inheritable. if cwd is not None: try: os.chdir(cwd) except OSError as e: e._failed_chdir = True raise # Python 3.9 if umask >= 0: os.umask(umask) # XXX: CPython does _Py_RestoreSignals here. # Then setsid() based on ??? try: if gids: os.setgroups(gids) if gid: os.setregid(gid, gid) if uid: os.setreuid(uid, uid) if process_group is not None: os.setpgid(0, process_group) except OSError as e: e._failed_chuser = True raise if preexec_fn: preexec_fn() # Close all other fds, if asked for. This must be done # after preexec_fn runs. if close_fds: fds_to_keep = set(pass_fds) fds_to_keep.add(errpipe_write) self._close_fds(fds_to_keep, errpipe_write) if restore_signals: # restore the documented signals back to sig_dfl; # not all will be defined on every platform for sig in 'SIGPIPE', 'SIGXFZ', 'SIGXFSZ': sig = getattr(signal, sig, None) if sig is not None: signal.signal(sig, signal.SIG_DFL) if start_new_session: os.setsid() try: if env is None: os.execvp(executable, args) else: # Python 3.6 started testing for # bytes values in the env; it also # started encoding strs using # fsencode and using a lower-level # API that takes a list of keys # and values. We don't have access # to that API, so we go the reverse direction. env = {os.fsdecode(k) if isinstance(k, bytes) else k: os.fsdecode(v) if isinstance(v, bytes) else v for k, v in env.items()} os.execvpe(executable, args, env) except OSError as e: e._failed_exec = True raise except: exc_type, exc_value, tb = sys.exc_info() # Save the traceback and attach it to the exception object exc_lines = traceback.format_exception(exc_type, exc_value, tb) exc_value.child_traceback = ''.join(exc_lines) os.write(errpipe_write, pickle.dumps(exc_value)) finally: # Make sure that the process exits no matter what. # The return code does not matter much as it won't be # reported to the application os._exit(1) # Parent self._child_created = True if gc_was_enabled: gc.enable() finally: # be sure the FD is closed no matter what os.close(errpipe_write) # self._devnull is not always defined. devnull_fd = getattr(self, '_devnull', None) if p2cread != -1 and p2cwrite != -1 and p2cread != devnull_fd: os.close(p2cread) if c2pwrite != -1 and c2pread != -1 and c2pwrite != devnull_fd: os.close(c2pwrite) if errwrite != -1 and errread != -1 and errwrite != devnull_fd: os.close(errwrite) if devnull_fd is not None: os.close(devnull_fd) # Prevent a double close of these fds from __init__ on error. self._closed_child_pipe_fds = True # Wait for exec to fail or succeed; possibly raising exception errpipe_read = FileObject(errpipe_read, 'rb') data = errpipe_read.read() finally: try: if hasattr(errpipe_read, 'close'): errpipe_read.close() else: os.close(errpipe_read) except OSError: # Especially on PyPy, we sometimes see the above # `os.close(errpipe_read)` raise an OSError. # It's not entirely clear why, but it happens in # InterprocessSignalTests.test_main sometimes, which must mean # we have some sort of race condition. pass finally: errpipe_read = -1 if data != b"": self.wait() child_exception = pickle.loads(data) for fd in (p2cwrite, c2pread, errread): if fd is not None and fd != -1: os.close(fd) if isinstance(child_exception, OSError): child_exception.filename = executable if hasattr(child_exception, '_failed_chdir'): child_exception.filename = cwd if getattr(child_exception, '_failed_chuser', False): child_exception.filename = None > raise child_exception E OSError: [Errno 8] Exec format error: 'locust' /usr/lib/python3/dist-packages/gevent/subprocess.py:1838: OSError _________________ DistributedIntegrationTests.test_json_schema _________________ self = def test_json_schema(self): LOCUSTFILE_CONTENT = textwrap.dedent( """ from locust import HttpUser, task, constant class QuickstartUser(HttpUser): wait_time = constant(1) @task def hello_world(self): self.client.get("/") """ ) with mock_locustfile(content=LOCUSTFILE_CONTENT) as mocked: > proc = subprocess.Popen( [ "locust", "-f", mocked.file_path, "--host", "http://google.com", "--headless", "-u", "1", "-t", "2s", "--json", ], stderr=DEVNULL, stdout=PIPE, text=True, ) locust/test/test_main.py:1848: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3/dist-packages/gevent/subprocess.py:808: in __init__ self._execute_child(args, executable, preexec_fn, close_fds, _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = args = ['locust', '-f', '/build/reproducible-path/locust-2.24.0/locust/test/mock_locustfile_1715255812_9661632_97278.py', '--host', 'http://google.com', '--headless', ...] executable = 'locust', preexec_fn = None, close_fds = True, pass_fds = () cwd = None, env = None, universal_newlines = None, startupinfo = None creationflags = 0, shell = False, p2cread = -1, p2cwrite = -1, c2pread = 11 c2pwrite = 81, errread = -1, errwrite = 82, restore_signals = True, gid = None gids = None, uid = None, umask = -1, start_new_session = False process_group = None def _execute_child(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, universal_newlines, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, restore_signals, gid, gids, uid, umask, start_new_session, process_group): """Execute program (POSIX version)""" if isinstance(args, (str, bytes)): args = [args] elif isinstance(args, PathLike): if shell: raise TypeError('path-like args is not allowed when ' 'shell is true') args = [fsencode(args)] # os.PathLike -> [str] else: args = list(args) if shell: # On Android the default shell is at '/system/bin/sh'. unix_shell = ( '/system/bin/sh' if hasattr(sys, 'getandroidapilevel') else '/bin/sh' ) args = [unix_shell, "-c"] + args if executable: args[0] = executable if executable is None: executable = args[0] self._loop.install_sigchld() # For transferring possible exec failure from child to parent # The first char specifies the exception type: 0 means # OSError, 1 means some other error. errpipe_read, errpipe_write = self.pipe_cloexec() # errpipe_write must not be in the standard io 0, 1, or 2 fd range. low_fds_to_close = [] while errpipe_write < 3: low_fds_to_close.append(errpipe_write) errpipe_write = os.dup(errpipe_write) for low_fd in low_fds_to_close: os.close(low_fd) try: try: gc_was_enabled = gc.isenabled() # Disable gc to avoid bug where gc -> file_dealloc -> # write to stderr -> hang. http://bugs.python.org/issue1336 gc.disable() try: self.pid = fork_and_watch(self._on_child, self._loop, True, fork) except: if gc_was_enabled: gc.enable() raise if self.pid == 0: # Child # In various places on the child side of things, we catch OSError # and add attributes to it that detail where in the process we failed; # like all exceptions until we have exec'd, this exception is pickled # and sent to the parent to raise in the calling process. # The parent uses this to decide how to treat that exception, # adjusting certain information about it as needed. # # Python 3.11.8 --- yes, a minor patch release --- stopped # letting the 'filename' parameter get set in the resulting # exception for many cases. We're not quite interpreting this # the same way the stdlib is, I'm sure, but this makes the stdlib # tests pass. # XXX: Technically we're doing a lot of stuff here that # may not be safe to do before a exec(), depending on the OS. # CPython 3 goes to great lengths to precompute a lot # of this info before the fork and pass it all to C functions that # try hard not to call things like malloc(). (Of course, # CPython 2 pretty much did what we're doing.) try: # Close parent's pipe ends if p2cwrite != -1: os.close(p2cwrite) if c2pread != -1: os.close(c2pread) if errread != -1: os.close(errread) os.close(errpipe_read) # When duping fds, if there arises a situation # where one of the fds is either 0, 1 or 2, it # is possible that it is overwritten (#12607). if c2pwrite == 0: c2pwrite = os.dup(c2pwrite) _set_inheritable(c2pwrite, False) while errwrite in (0, 1): errwrite = os.dup(errwrite) _set_inheritable(errwrite, False) # Dup fds for child def _dup2(existing, desired): # dup2() removes the CLOEXEC flag but # we must do it ourselves if dup2() # would be a no-op (issue #10806). if existing == desired: self._set_cloexec_flag(existing, False) elif existing != -1: os.dup2(existing, desired) try: self._remove_nonblock_flag(desired) except OSError: # Ignore EBADF, it may not actually be # open yet. # Tested beginning in 3.7.0b3 test_subprocess.py pass _dup2(p2cread, 0) _dup2(c2pwrite, 1) _dup2(errwrite, 2) # Close pipe fds. Make sure we don't close the # same fd more than once, or standard fds. if not True: closed = set([None]) for fd in (p2cread, c2pwrite, errwrite): if fd not in closed and fd > 2: os.close(fd) closed.add(fd) # Python 3 (with a working set_inheritable): # We no longer manually close p2cread, # c2pwrite, and errwrite here as # _close_open_fds takes care when it is # not already non-inheritable. if cwd is not None: try: os.chdir(cwd) except OSError as e: e._failed_chdir = True raise # Python 3.9 if umask >= 0: os.umask(umask) # XXX: CPython does _Py_RestoreSignals here. # Then setsid() based on ??? try: if gids: os.setgroups(gids) if gid: os.setregid(gid, gid) if uid: os.setreuid(uid, uid) if process_group is not None: os.setpgid(0, process_group) except OSError as e: e._failed_chuser = True raise if preexec_fn: preexec_fn() # Close all other fds, if asked for. This must be done # after preexec_fn runs. if close_fds: fds_to_keep = set(pass_fds) fds_to_keep.add(errpipe_write) self._close_fds(fds_to_keep, errpipe_write) if restore_signals: # restore the documented signals back to sig_dfl; # not all will be defined on every platform for sig in 'SIGPIPE', 'SIGXFZ', 'SIGXFSZ': sig = getattr(signal, sig, None) if sig is not None: signal.signal(sig, signal.SIG_DFL) if start_new_session: os.setsid() try: if env is None: os.execvp(executable, args) else: # Python 3.6 started testing for # bytes values in the env; it also # started encoding strs using # fsencode and using a lower-level # API that takes a list of keys # and values. We don't have access # to that API, so we go the reverse direction. env = {os.fsdecode(k) if isinstance(k, bytes) else k: os.fsdecode(v) if isinstance(v, bytes) else v for k, v in env.items()} os.execvpe(executable, args, env) except OSError as e: e._failed_exec = True raise except: exc_type, exc_value, tb = sys.exc_info() # Save the traceback and attach it to the exception object exc_lines = traceback.format_exception(exc_type, exc_value, tb) exc_value.child_traceback = ''.join(exc_lines) os.write(errpipe_write, pickle.dumps(exc_value)) finally: # Make sure that the process exits no matter what. # The return code does not matter much as it won't be # reported to the application os._exit(1) # Parent self._child_created = True if gc_was_enabled: gc.enable() finally: # be sure the FD is closed no matter what os.close(errpipe_write) # self._devnull is not always defined. devnull_fd = getattr(self, '_devnull', None) if p2cread != -1 and p2cwrite != -1 and p2cread != devnull_fd: os.close(p2cread) if c2pwrite != -1 and c2pread != -1 and c2pwrite != devnull_fd: os.close(c2pwrite) if errwrite != -1 and errread != -1 and errwrite != devnull_fd: os.close(errwrite) if devnull_fd is not None: os.close(devnull_fd) # Prevent a double close of these fds from __init__ on error. self._closed_child_pipe_fds = True # Wait for exec to fail or succeed; possibly raising exception errpipe_read = FileObject(errpipe_read, 'rb') data = errpipe_read.read() finally: try: if hasattr(errpipe_read, 'close'): errpipe_read.close() else: os.close(errpipe_read) except OSError: # Especially on PyPy, we sometimes see the above # `os.close(errpipe_read)` raise an OSError. # It's not entirely clear why, but it happens in # InterprocessSignalTests.test_main sometimes, which must mean # we have some sort of race condition. pass finally: errpipe_read = -1 if data != b"": self.wait() child_exception = pickle.loads(data) for fd in (p2cwrite, c2pread, errread): if fd is not None and fd != -1: os.close(fd) if isinstance(child_exception, OSError): child_exception.filename = executable if hasattr(child_exception, '_failed_chdir'): child_exception.filename = cwd if getattr(child_exception, '_failed_chuser', False): child_exception.filename = None > raise child_exception E OSError: [Errno 8] Exec format error: 'locust' /usr/lib/python3/dist-packages/gevent/subprocess.py:1838: OSError ___________ DistributedIntegrationTests.test_locustfile_distribution ___________ self = def test_locustfile_distribution(self): LOCUSTFILE_CONTENT = textwrap.dedent( """ from locust import User, task, constant class User1(User): wait_time = constant(1) @task def t(self): pass """ ) with mock_locustfile(content=LOCUSTFILE_CONTENT) as mocked: > proc = subprocess.Popen( [ "locust", "-f", mocked.file_path, "--headless", "--master", "--expect-workers", "2", "-t", "1s", ], stderr=STDOUT, stdout=PIPE, text=True, ) locust/test/test_main.py:1679: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3/dist-packages/gevent/subprocess.py:808: in __init__ self._execute_child(args, executable, preexec_fn, close_fds, _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = args = ['locust', '-f', '/build/reproducible-path/locust-2.24.0/locust/test/mock_locustfile_1715255813_156301_98048.py', '--headless', '--master', '--expect-workers', ...] executable = 'locust', preexec_fn = None, close_fds = True, pass_fds = () cwd = None, env = None, universal_newlines = None, startupinfo = None creationflags = 0, shell = False, p2cread = -1, p2cwrite = -1, c2pread = 11 c2pwrite = 81, errread = -1, errwrite = 81, restore_signals = True, gid = None gids = None, uid = None, umask = -1, start_new_session = False process_group = None def _execute_child(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, universal_newlines, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, restore_signals, gid, gids, uid, umask, start_new_session, process_group): """Execute program (POSIX version)""" if isinstance(args, (str, bytes)): args = [args] elif isinstance(args, PathLike): if shell: raise TypeError('path-like args is not allowed when ' 'shell is true') args = [fsencode(args)] # os.PathLike -> [str] else: args = list(args) if shell: # On Android the default shell is at '/system/bin/sh'. unix_shell = ( '/system/bin/sh' if hasattr(sys, 'getandroidapilevel') else '/bin/sh' ) args = [unix_shell, "-c"] + args if executable: args[0] = executable if executable is None: executable = args[0] self._loop.install_sigchld() # For transferring possible exec failure from child to parent # The first char specifies the exception type: 0 means # OSError, 1 means some other error. errpipe_read, errpipe_write = self.pipe_cloexec() # errpipe_write must not be in the standard io 0, 1, or 2 fd range. low_fds_to_close = [] while errpipe_write < 3: low_fds_to_close.append(errpipe_write) errpipe_write = os.dup(errpipe_write) for low_fd in low_fds_to_close: os.close(low_fd) try: try: gc_was_enabled = gc.isenabled() # Disable gc to avoid bug where gc -> file_dealloc -> # write to stderr -> hang. http://bugs.python.org/issue1336 gc.disable() try: self.pid = fork_and_watch(self._on_child, self._loop, True, fork) except: if gc_was_enabled: gc.enable() raise if self.pid == 0: # Child # In various places on the child side of things, we catch OSError # and add attributes to it that detail where in the process we failed; # like all exceptions until we have exec'd, this exception is pickled # and sent to the parent to raise in the calling process. # The parent uses this to decide how to treat that exception, # adjusting certain information about it as needed. # # Python 3.11.8 --- yes, a minor patch release --- stopped # letting the 'filename' parameter get set in the resulting # exception for many cases. We're not quite interpreting this # the same way the stdlib is, I'm sure, but this makes the stdlib # tests pass. # XXX: Technically we're doing a lot of stuff here that # may not be safe to do before a exec(), depending on the OS. # CPython 3 goes to great lengths to precompute a lot # of this info before the fork and pass it all to C functions that # try hard not to call things like malloc(). (Of course, # CPython 2 pretty much did what we're doing.) try: # Close parent's pipe ends if p2cwrite != -1: os.close(p2cwrite) if c2pread != -1: os.close(c2pread) if errread != -1: os.close(errread) os.close(errpipe_read) # When duping fds, if there arises a situation # where one of the fds is either 0, 1 or 2, it # is possible that it is overwritten (#12607). if c2pwrite == 0: c2pwrite = os.dup(c2pwrite) _set_inheritable(c2pwrite, False) while errwrite in (0, 1): errwrite = os.dup(errwrite) _set_inheritable(errwrite, False) # Dup fds for child def _dup2(existing, desired): # dup2() removes the CLOEXEC flag but # we must do it ourselves if dup2() # would be a no-op (issue #10806). if existing == desired: self._set_cloexec_flag(existing, False) elif existing != -1: os.dup2(existing, desired) try: self._remove_nonblock_flag(desired) except OSError: # Ignore EBADF, it may not actually be # open yet. # Tested beginning in 3.7.0b3 test_subprocess.py pass _dup2(p2cread, 0) _dup2(c2pwrite, 1) _dup2(errwrite, 2) # Close pipe fds. Make sure we don't close the # same fd more than once, or standard fds. if not True: closed = set([None]) for fd in (p2cread, c2pwrite, errwrite): if fd not in closed and fd > 2: os.close(fd) closed.add(fd) # Python 3 (with a working set_inheritable): # We no longer manually close p2cread, # c2pwrite, and errwrite here as # _close_open_fds takes care when it is # not already non-inheritable. if cwd is not None: try: os.chdir(cwd) except OSError as e: e._failed_chdir = True raise # Python 3.9 if umask >= 0: os.umask(umask) # XXX: CPython does _Py_RestoreSignals here. # Then setsid() based on ??? try: if gids: os.setgroups(gids) if gid: os.setregid(gid, gid) if uid: os.setreuid(uid, uid) if process_group is not None: os.setpgid(0, process_group) except OSError as e: e._failed_chuser = True raise if preexec_fn: preexec_fn() # Close all other fds, if asked for. This must be done # after preexec_fn runs. if close_fds: fds_to_keep = set(pass_fds) fds_to_keep.add(errpipe_write) self._close_fds(fds_to_keep, errpipe_write) if restore_signals: # restore the documented signals back to sig_dfl; # not all will be defined on every platform for sig in 'SIGPIPE', 'SIGXFZ', 'SIGXFSZ': sig = getattr(signal, sig, None) if sig is not None: signal.signal(sig, signal.SIG_DFL) if start_new_session: os.setsid() try: if env is None: os.execvp(executable, args) else: # Python 3.6 started testing for # bytes values in the env; it also # started encoding strs using # fsencode and using a lower-level # API that takes a list of keys # and values. We don't have access # to that API, so we go the reverse direction. env = {os.fsdecode(k) if isinstance(k, bytes) else k: os.fsdecode(v) if isinstance(v, bytes) else v for k, v in env.items()} os.execvpe(executable, args, env) except OSError as e: e._failed_exec = True raise except: exc_type, exc_value, tb = sys.exc_info() # Save the traceback and attach it to the exception object exc_lines = traceback.format_exception(exc_type, exc_value, tb) exc_value.child_traceback = ''.join(exc_lines) os.write(errpipe_write, pickle.dumps(exc_value)) finally: # Make sure that the process exits no matter what. # The return code does not matter much as it won't be # reported to the application os._exit(1) # Parent self._child_created = True if gc_was_enabled: gc.enable() finally: # be sure the FD is closed no matter what os.close(errpipe_write) # self._devnull is not always defined. devnull_fd = getattr(self, '_devnull', None) if p2cread != -1 and p2cwrite != -1 and p2cread != devnull_fd: os.close(p2cread) if c2pwrite != -1 and c2pread != -1 and c2pwrite != devnull_fd: os.close(c2pwrite) if errwrite != -1 and errread != -1 and errwrite != devnull_fd: os.close(errwrite) if devnull_fd is not None: os.close(devnull_fd) # Prevent a double close of these fds from __init__ on error. self._closed_child_pipe_fds = True # Wait for exec to fail or succeed; possibly raising exception errpipe_read = FileObject(errpipe_read, 'rb') data = errpipe_read.read() finally: try: if hasattr(errpipe_read, 'close'): errpipe_read.close() else: os.close(errpipe_read) except OSError: # Especially on PyPy, we sometimes see the above # `os.close(errpipe_read)` raise an OSError. # It's not entirely clear why, but it happens in # InterprocessSignalTests.test_main sometimes, which must mean # we have some sort of race condition. pass finally: errpipe_read = -1 if data != b"": self.wait() child_exception = pickle.loads(data) for fd in (p2cwrite, c2pread, errread): if fd is not None and fd != -1: os.close(fd) if isinstance(child_exception, OSError): child_exception.filename = executable if hasattr(child_exception, '_failed_chdir'): child_exception.filename = cwd if getattr(child_exception, '_failed_chuser', False): child_exception.filename = None > raise child_exception E OSError: [Errno 8] Exec format error: 'locust' /usr/lib/python3/dist-packages/gevent/subprocess.py:1838: OSError _ DistributedIntegrationTests.test_locustfile_distribution_with_workers_started_first _ self = def test_locustfile_distribution_with_workers_started_first(self): LOCUSTFILE_CONTENT = textwrap.dedent( """ from locust import User, task, constant class User1(User): wait_time = constant(1) @task def t(self): print("hello") """ ) with mock_locustfile(content=LOCUSTFILE_CONTENT) as mocked: > proc_worker = subprocess.Popen( [ "locust", "-f", "-", "--worker", ], stderr=STDOUT, stdout=PIPE, text=True, ) locust/test/test_main.py:1751: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3/dist-packages/gevent/subprocess.py:808: in __init__ self._execute_child(args, executable, preexec_fn, close_fds, _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = args = ['locust', '-f', '-', '--worker'], executable = 'locust' preexec_fn = None, close_fds = True, pass_fds = (), cwd = None, env = None universal_newlines = None, startupinfo = None, creationflags = 0, shell = False p2cread = -1, p2cwrite = -1, c2pread = 11, c2pwrite = 81, errread = -1 errwrite = 81, restore_signals = True, gid = None, gids = None, uid = None umask = -1, start_new_session = False, process_group = None def _execute_child(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, universal_newlines, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, restore_signals, gid, gids, uid, umask, start_new_session, process_group): """Execute program (POSIX version)""" if isinstance(args, (str, bytes)): args = [args] elif isinstance(args, PathLike): if shell: raise TypeError('path-like args is not allowed when ' 'shell is true') args = [fsencode(args)] # os.PathLike -> [str] else: args = list(args) if shell: # On Android the default shell is at '/system/bin/sh'. unix_shell = ( '/system/bin/sh' if hasattr(sys, 'getandroidapilevel') else '/bin/sh' ) args = [unix_shell, "-c"] + args if executable: args[0] = executable if executable is None: executable = args[0] self._loop.install_sigchld() # For transferring possible exec failure from child to parent # The first char specifies the exception type: 0 means # OSError, 1 means some other error. errpipe_read, errpipe_write = self.pipe_cloexec() # errpipe_write must not be in the standard io 0, 1, or 2 fd range. low_fds_to_close = [] while errpipe_write < 3: low_fds_to_close.append(errpipe_write) errpipe_write = os.dup(errpipe_write) for low_fd in low_fds_to_close: os.close(low_fd) try: try: gc_was_enabled = gc.isenabled() # Disable gc to avoid bug where gc -> file_dealloc -> # write to stderr -> hang. http://bugs.python.org/issue1336 gc.disable() try: self.pid = fork_and_watch(self._on_child, self._loop, True, fork) except: if gc_was_enabled: gc.enable() raise if self.pid == 0: # Child # In various places on the child side of things, we catch OSError # and add attributes to it that detail where in the process we failed; # like all exceptions until we have exec'd, this exception is pickled # and sent to the parent to raise in the calling process. # The parent uses this to decide how to treat that exception, # adjusting certain information about it as needed. # # Python 3.11.8 --- yes, a minor patch release --- stopped # letting the 'filename' parameter get set in the resulting # exception for many cases. We're not quite interpreting this # the same way the stdlib is, I'm sure, but this makes the stdlib # tests pass. # XXX: Technically we're doing a lot of stuff here that # may not be safe to do before a exec(), depending on the OS. # CPython 3 goes to great lengths to precompute a lot # of this info before the fork and pass it all to C functions that # try hard not to call things like malloc(). (Of course, # CPython 2 pretty much did what we're doing.) try: # Close parent's pipe ends if p2cwrite != -1: os.close(p2cwrite) if c2pread != -1: os.close(c2pread) if errread != -1: os.close(errread) os.close(errpipe_read) # When duping fds, if there arises a situation # where one of the fds is either 0, 1 or 2, it # is possible that it is overwritten (#12607). if c2pwrite == 0: c2pwrite = os.dup(c2pwrite) _set_inheritable(c2pwrite, False) while errwrite in (0, 1): errwrite = os.dup(errwrite) _set_inheritable(errwrite, False) # Dup fds for child def _dup2(existing, desired): # dup2() removes the CLOEXEC flag but # we must do it ourselves if dup2() # would be a no-op (issue #10806). if existing == desired: self._set_cloexec_flag(existing, False) elif existing != -1: os.dup2(existing, desired) try: self._remove_nonblock_flag(desired) except OSError: # Ignore EBADF, it may not actually be # open yet. # Tested beginning in 3.7.0b3 test_subprocess.py pass _dup2(p2cread, 0) _dup2(c2pwrite, 1) _dup2(errwrite, 2) # Close pipe fds. Make sure we don't close the # same fd more than once, or standard fds. if not True: closed = set([None]) for fd in (p2cread, c2pwrite, errwrite): if fd not in closed and fd > 2: os.close(fd) closed.add(fd) # Python 3 (with a working set_inheritable): # We no longer manually close p2cread, # c2pwrite, and errwrite here as # _close_open_fds takes care when it is # not already non-inheritable. if cwd is not None: try: os.chdir(cwd) except OSError as e: e._failed_chdir = True raise # Python 3.9 if umask >= 0: os.umask(umask) # XXX: CPython does _Py_RestoreSignals here. # Then setsid() based on ??? try: if gids: os.setgroups(gids) if gid: os.setregid(gid, gid) if uid: os.setreuid(uid, uid) if process_group is not None: os.setpgid(0, process_group) except OSError as e: e._failed_chuser = True raise if preexec_fn: preexec_fn() # Close all other fds, if asked for. This must be done # after preexec_fn runs. if close_fds: fds_to_keep = set(pass_fds) fds_to_keep.add(errpipe_write) self._close_fds(fds_to_keep, errpipe_write) if restore_signals: # restore the documented signals back to sig_dfl; # not all will be defined on every platform for sig in 'SIGPIPE', 'SIGXFZ', 'SIGXFSZ': sig = getattr(signal, sig, None) if sig is not None: signal.signal(sig, signal.SIG_DFL) if start_new_session: os.setsid() try: if env is None: os.execvp(executable, args) else: # Python 3.6 started testing for # bytes values in the env; it also # started encoding strs using # fsencode and using a lower-level # API that takes a list of keys # and values. We don't have access # to that API, so we go the reverse direction. env = {os.fsdecode(k) if isinstance(k, bytes) else k: os.fsdecode(v) if isinstance(v, bytes) else v for k, v in env.items()} os.execvpe(executable, args, env) except OSError as e: e._failed_exec = True raise except: exc_type, exc_value, tb = sys.exc_info() # Save the traceback and attach it to the exception object exc_lines = traceback.format_exception(exc_type, exc_value, tb) exc_value.child_traceback = ''.join(exc_lines) os.write(errpipe_write, pickle.dumps(exc_value)) finally: # Make sure that the process exits no matter what. # The return code does not matter much as it won't be # reported to the application os._exit(1) # Parent self._child_created = True if gc_was_enabled: gc.enable() finally: # be sure the FD is closed no matter what os.close(errpipe_write) # self._devnull is not always defined. devnull_fd = getattr(self, '_devnull', None) if p2cread != -1 and p2cwrite != -1 and p2cread != devnull_fd: os.close(p2cread) if c2pwrite != -1 and c2pread != -1 and c2pwrite != devnull_fd: os.close(c2pwrite) if errwrite != -1 and errread != -1 and errwrite != devnull_fd: os.close(errwrite) if devnull_fd is not None: os.close(devnull_fd) # Prevent a double close of these fds from __init__ on error. self._closed_child_pipe_fds = True # Wait for exec to fail or succeed; possibly raising exception errpipe_read = FileObject(errpipe_read, 'rb') data = errpipe_read.read() finally: try: if hasattr(errpipe_read, 'close'): errpipe_read.close() else: os.close(errpipe_read) except OSError: # Especially on PyPy, we sometimes see the above # `os.close(errpipe_read)` raise an OSError. # It's not entirely clear why, but it happens in # InterprocessSignalTests.test_main sometimes, which must mean # we have some sort of race condition. pass finally: errpipe_read = -1 if data != b"": self.wait() child_exception = pickle.loads(data) for fd in (p2cwrite, c2pread, errread): if fd is not None and fd != -1: os.close(fd) if isinstance(child_exception, OSError): child_exception.filename = executable if hasattr(child_exception, '_failed_chdir'): child_exception.filename = cwd if getattr(child_exception, '_failed_chuser', False): child_exception.filename = None > raise child_exception E OSError: [Errno 8] Exec format error: 'locust' /usr/lib/python3/dist-packages/gevent/subprocess.py:1838: OSError __________________ DistributedIntegrationTests.test_processes __________________ self = @unittest.skipIf(os.name == "nt", reason="--processes doesnt work on windows") def test_processes(self): with mock_locustfile() as mocked: command = f"locust -f {mocked.file_path} --processes 4 --headless --run-time 1 --exit-code-on-error 0" proc = subprocess.Popen( command, shell=True, stdout=PIPE, stderr=PIPE, text=True, ) try: _, stderr = proc.communicate(timeout=9) except Exception: proc.kill() assert False, f"locust process never finished: {command}" self.assertNotIn("Traceback", stderr) > self.assertIn("(index 3) reported as ready", stderr) E AssertionError: '(index 3) reported as ready' not found in '/build/reproducible-path/locust-2.24.0/debian/locust: line 2: from: command not found\n/build/reproducible-path/locust-2.24.0/debian/locust: line 5: syntax error: unexpected end of file\n' locust/test/test_main.py:1993: AssertionError ____________ DistributedIntegrationTests.test_processes_autodetect _____________ self = @unittest.skipIf(os.name == "nt", reason="--processes doesnt work on windows") def test_processes_autodetect(self): with mock_locustfile() as mocked: command = f"locust -f {mocked.file_path} --processes -1 --headless --run-time 1 --exit-code-on-error 0" proc = subprocess.Popen( command, shell=True, stdout=PIPE, stderr=PIPE, text=True, ) try: _, stderr = proc.communicate(timeout=9) except Exception: proc.kill() assert False, f"locust process never finished: {command}" self.assertNotIn("Traceback", stderr) > self.assertIn("(index 0) reported as ready", stderr) E AssertionError: '(index 0) reported as ready' not found in '/build/reproducible-path/locust-2.24.0/debian/locust: line 2: from: command not found\n/build/reproducible-path/locust-2.24.0/debian/locust: line 5: syntax error: unexpected end of file\n' locust/test/test_main.py:2013: AssertionError ______________ DistributedIntegrationTests.test_processes_ctrl_c _______________ self = @unittest.skipIf(os.name == "nt", reason="--processes doesnt work on windows") def test_processes_ctrl_c(self): with mock_locustfile() as mocked: > proc = psutil.Popen( # use psutil.Popen instead of subprocess.Popen to use extra features [ "locust", "-f", mocked.file_path, "--processes", "4", "--headless", "-L", "DEBUG", ], stdout=PIPE, stderr=PIPE, text=True, ) locust/test/test_main.py:2064: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3/dist-packages/psutil/__init__.py:1378: in __init__ self.__subproc = subprocess.Popen(*args, **kwargs) /usr/lib/python3/dist-packages/gevent/subprocess.py:808: in __init__ self._execute_child(args, executable, preexec_fn, close_fds, _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = args = ['locust', '-f', '/build/reproducible-path/locust-2.24.0/locust/test/mock_locustfile_1715255813_6901526_35582.py', '--processes', '4', '--headless', ...] executable = 'locust', preexec_fn = None, close_fds = True, pass_fds = () cwd = None, env = None, universal_newlines = None, startupinfo = None creationflags = 0, shell = False, p2cread = -1, p2cwrite = -1, c2pread = 11 c2pwrite = 81, errread = 82, errwrite = 83, restore_signals = True, gid = None gids = None, uid = None, umask = -1, start_new_session = False process_group = None def _execute_child(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, universal_newlines, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, restore_signals, gid, gids, uid, umask, start_new_session, process_group): """Execute program (POSIX version)""" if isinstance(args, (str, bytes)): args = [args] elif isinstance(args, PathLike): if shell: raise TypeError('path-like args is not allowed when ' 'shell is true') args = [fsencode(args)] # os.PathLike -> [str] else: args = list(args) if shell: # On Android the default shell is at '/system/bin/sh'. unix_shell = ( '/system/bin/sh' if hasattr(sys, 'getandroidapilevel') else '/bin/sh' ) args = [unix_shell, "-c"] + args if executable: args[0] = executable if executable is None: executable = args[0] self._loop.install_sigchld() # For transferring possible exec failure from child to parent # The first char specifies the exception type: 0 means # OSError, 1 means some other error. errpipe_read, errpipe_write = self.pipe_cloexec() # errpipe_write must not be in the standard io 0, 1, or 2 fd range. low_fds_to_close = [] while errpipe_write < 3: low_fds_to_close.append(errpipe_write) errpipe_write = os.dup(errpipe_write) for low_fd in low_fds_to_close: os.close(low_fd) try: try: gc_was_enabled = gc.isenabled() # Disable gc to avoid bug where gc -> file_dealloc -> # write to stderr -> hang. http://bugs.python.org/issue1336 gc.disable() try: self.pid = fork_and_watch(self._on_child, self._loop, True, fork) except: if gc_was_enabled: gc.enable() raise if self.pid == 0: # Child # In various places on the child side of things, we catch OSError # and add attributes to it that detail where in the process we failed; # like all exceptions until we have exec'd, this exception is pickled # and sent to the parent to raise in the calling process. # The parent uses this to decide how to treat that exception, # adjusting certain information about it as needed. # # Python 3.11.8 --- yes, a minor patch release --- stopped # letting the 'filename' parameter get set in the resulting # exception for many cases. We're not quite interpreting this # the same way the stdlib is, I'm sure, but this makes the stdlib # tests pass. # XXX: Technically we're doing a lot of stuff here that # may not be safe to do before a exec(), depending on the OS. # CPython 3 goes to great lengths to precompute a lot # of this info before the fork and pass it all to C functions that # try hard not to call things like malloc(). (Of course, # CPython 2 pretty much did what we're doing.) try: # Close parent's pipe ends if p2cwrite != -1: os.close(p2cwrite) if c2pread != -1: os.close(c2pread) if errread != -1: os.close(errread) os.close(errpipe_read) # When duping fds, if there arises a situation # where one of the fds is either 0, 1 or 2, it # is possible that it is overwritten (#12607). if c2pwrite == 0: c2pwrite = os.dup(c2pwrite) _set_inheritable(c2pwrite, False) while errwrite in (0, 1): errwrite = os.dup(errwrite) _set_inheritable(errwrite, False) # Dup fds for child def _dup2(existing, desired): # dup2() removes the CLOEXEC flag but # we must do it ourselves if dup2() # would be a no-op (issue #10806). if existing == desired: self._set_cloexec_flag(existing, False) elif existing != -1: os.dup2(existing, desired) try: self._remove_nonblock_flag(desired) except OSError: # Ignore EBADF, it may not actually be # open yet. # Tested beginning in 3.7.0b3 test_subprocess.py pass _dup2(p2cread, 0) _dup2(c2pwrite, 1) _dup2(errwrite, 2) # Close pipe fds. Make sure we don't close the # same fd more than once, or standard fds. if not True: closed = set([None]) for fd in (p2cread, c2pwrite, errwrite): if fd not in closed and fd > 2: os.close(fd) closed.add(fd) # Python 3 (with a working set_inheritable): # We no longer manually close p2cread, # c2pwrite, and errwrite here as # _close_open_fds takes care when it is # not already non-inheritable. if cwd is not None: try: os.chdir(cwd) except OSError as e: e._failed_chdir = True raise # Python 3.9 if umask >= 0: os.umask(umask) # XXX: CPython does _Py_RestoreSignals here. # Then setsid() based on ??? try: if gids: os.setgroups(gids) if gid: os.setregid(gid, gid) if uid: os.setreuid(uid, uid) if process_group is not None: os.setpgid(0, process_group) except OSError as e: e._failed_chuser = True raise if preexec_fn: preexec_fn() # Close all other fds, if asked for. This must be done # after preexec_fn runs. if close_fds: fds_to_keep = set(pass_fds) fds_to_keep.add(errpipe_write) self._close_fds(fds_to_keep, errpipe_write) if restore_signals: # restore the documented signals back to sig_dfl; # not all will be defined on every platform for sig in 'SIGPIPE', 'SIGXFZ', 'SIGXFSZ': sig = getattr(signal, sig, None) if sig is not None: signal.signal(sig, signal.SIG_DFL) if start_new_session: os.setsid() try: if env is None: os.execvp(executable, args) else: # Python 3.6 started testing for # bytes values in the env; it also # started encoding strs using # fsencode and using a lower-level # API that takes a list of keys # and values. We don't have access # to that API, so we go the reverse direction. env = {os.fsdecode(k) if isinstance(k, bytes) else k: os.fsdecode(v) if isinstance(v, bytes) else v for k, v in env.items()} os.execvpe(executable, args, env) except OSError as e: e._failed_exec = True raise except: exc_type, exc_value, tb = sys.exc_info() # Save the traceback and attach it to the exception object exc_lines = traceback.format_exception(exc_type, exc_value, tb) exc_value.child_traceback = ''.join(exc_lines) os.write(errpipe_write, pickle.dumps(exc_value)) finally: # Make sure that the process exits no matter what. # The return code does not matter much as it won't be # reported to the application os._exit(1) # Parent self._child_created = True if gc_was_enabled: gc.enable() finally: # be sure the FD is closed no matter what os.close(errpipe_write) # self._devnull is not always defined. devnull_fd = getattr(self, '_devnull', None) if p2cread != -1 and p2cwrite != -1 and p2cread != devnull_fd: os.close(p2cread) if c2pwrite != -1 and c2pread != -1 and c2pwrite != devnull_fd: os.close(c2pwrite) if errwrite != -1 and errread != -1 and errwrite != devnull_fd: os.close(errwrite) if devnull_fd is not None: os.close(devnull_fd) # Prevent a double close of these fds from __init__ on error. self._closed_child_pipe_fds = True # Wait for exec to fail or succeed; possibly raising exception errpipe_read = FileObject(errpipe_read, 'rb') data = errpipe_read.read() finally: try: if hasattr(errpipe_read, 'close'): errpipe_read.close() else: os.close(errpipe_read) except OSError: # Especially on PyPy, we sometimes see the above # `os.close(errpipe_read)` raise an OSError. # It's not entirely clear why, but it happens in # InterprocessSignalTests.test_main sometimes, which must mean # we have some sort of race condition. pass finally: errpipe_read = -1 if data != b"": self.wait() child_exception = pickle.loads(data) for fd in (p2cwrite, c2pread, errread): if fd is not None and fd != -1: os.close(fd) if isinstance(child_exception, OSError): child_exception.filename = executable if hasattr(child_exception, '_failed_chdir'): child_exception.filename = cwd if getattr(child_exception, '_failed_chuser', False): child_exception.filename = None > raise child_exception E OSError: [Errno 8] Exec format error: 'locust' /usr/lib/python3/dist-packages/gevent/subprocess.py:1838: OSError __ DistributedIntegrationTests.test_processes_error_doesnt_blow_up_completely __ self = @unittest.skipIf(os.name == "nt", reason="--processes doesnt work on windows") def test_processes_error_doesnt_blow_up_completely(self): with mock_locustfile() as mocked: > proc = subprocess.Popen( [ "locust", "-f", mocked.file_path, "--processes", "4", "-L", "DEBUG", "UserThatDoesntExist", ], stdout=PIPE, stderr=PIPE, text=True, ) locust/test/test_main.py:2162: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3/dist-packages/gevent/subprocess.py:808: in __init__ self._execute_child(args, executable, preexec_fn, close_fds, _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = args = ['locust', '-f', '/build/reproducible-path/locust-2.24.0/locust/test/mock_locustfile_1715255813_9592519_23119.py', '--processes', '4', '-L', ...] executable = 'locust', preexec_fn = None, close_fds = True, pass_fds = () cwd = None, env = None, universal_newlines = None, startupinfo = None creationflags = 0, shell = False, p2cread = -1, p2cwrite = -1, c2pread = 11 c2pwrite = 81, errread = 82, errwrite = 83, restore_signals = True, gid = None gids = None, uid = None, umask = -1, start_new_session = False process_group = None def _execute_child(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, universal_newlines, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, restore_signals, gid, gids, uid, umask, start_new_session, process_group): """Execute program (POSIX version)""" if isinstance(args, (str, bytes)): args = [args] elif isinstance(args, PathLike): if shell: raise TypeError('path-like args is not allowed when ' 'shell is true') args = [fsencode(args)] # os.PathLike -> [str] else: args = list(args) if shell: # On Android the default shell is at '/system/bin/sh'. unix_shell = ( '/system/bin/sh' if hasattr(sys, 'getandroidapilevel') else '/bin/sh' ) args = [unix_shell, "-c"] + args if executable: args[0] = executable if executable is None: executable = args[0] self._loop.install_sigchld() # For transferring possible exec failure from child to parent # The first char specifies the exception type: 0 means # OSError, 1 means some other error. errpipe_read, errpipe_write = self.pipe_cloexec() # errpipe_write must not be in the standard io 0, 1, or 2 fd range. low_fds_to_close = [] while errpipe_write < 3: low_fds_to_close.append(errpipe_write) errpipe_write = os.dup(errpipe_write) for low_fd in low_fds_to_close: os.close(low_fd) try: try: gc_was_enabled = gc.isenabled() # Disable gc to avoid bug where gc -> file_dealloc -> # write to stderr -> hang. http://bugs.python.org/issue1336 gc.disable() try: self.pid = fork_and_watch(self._on_child, self._loop, True, fork) except: if gc_was_enabled: gc.enable() raise if self.pid == 0: # Child # In various places on the child side of things, we catch OSError # and add attributes to it that detail where in the process we failed; # like all exceptions until we have exec'd, this exception is pickled # and sent to the parent to raise in the calling process. # The parent uses this to decide how to treat that exception, # adjusting certain information about it as needed. # # Python 3.11.8 --- yes, a minor patch release --- stopped # letting the 'filename' parameter get set in the resulting # exception for many cases. We're not quite interpreting this # the same way the stdlib is, I'm sure, but this makes the stdlib # tests pass. # XXX: Technically we're doing a lot of stuff here that # may not be safe to do before a exec(), depending on the OS. # CPython 3 goes to great lengths to precompute a lot # of this info before the fork and pass it all to C functions that # try hard not to call things like malloc(). (Of course, # CPython 2 pretty much did what we're doing.) try: # Close parent's pipe ends if p2cwrite != -1: os.close(p2cwrite) if c2pread != -1: os.close(c2pread) if errread != -1: os.close(errread) os.close(errpipe_read) # When duping fds, if there arises a situation # where one of the fds is either 0, 1 or 2, it # is possible that it is overwritten (#12607). if c2pwrite == 0: c2pwrite = os.dup(c2pwrite) _set_inheritable(c2pwrite, False) while errwrite in (0, 1): errwrite = os.dup(errwrite) _set_inheritable(errwrite, False) # Dup fds for child def _dup2(existing, desired): # dup2() removes the CLOEXEC flag but # we must do it ourselves if dup2() # would be a no-op (issue #10806). if existing == desired: self._set_cloexec_flag(existing, False) elif existing != -1: os.dup2(existing, desired) try: self._remove_nonblock_flag(desired) except OSError: # Ignore EBADF, it may not actually be # open yet. # Tested beginning in 3.7.0b3 test_subprocess.py pass _dup2(p2cread, 0) _dup2(c2pwrite, 1) _dup2(errwrite, 2) # Close pipe fds. Make sure we don't close the # same fd more than once, or standard fds. if not True: closed = set([None]) for fd in (p2cread, c2pwrite, errwrite): if fd not in closed and fd > 2: os.close(fd) closed.add(fd) # Python 3 (with a working set_inheritable): # We no longer manually close p2cread, # c2pwrite, and errwrite here as # _close_open_fds takes care when it is # not already non-inheritable. if cwd is not None: try: os.chdir(cwd) except OSError as e: e._failed_chdir = True raise # Python 3.9 if umask >= 0: os.umask(umask) # XXX: CPython does _Py_RestoreSignals here. # Then setsid() based on ??? try: if gids: os.setgroups(gids) if gid: os.setregid(gid, gid) if uid: os.setreuid(uid, uid) if process_group is not None: os.setpgid(0, process_group) except OSError as e: e._failed_chuser = True raise if preexec_fn: preexec_fn() # Close all other fds, if asked for. This must be done # after preexec_fn runs. if close_fds: fds_to_keep = set(pass_fds) fds_to_keep.add(errpipe_write) self._close_fds(fds_to_keep, errpipe_write) if restore_signals: # restore the documented signals back to sig_dfl; # not all will be defined on every platform for sig in 'SIGPIPE', 'SIGXFZ', 'SIGXFSZ': sig = getattr(signal, sig, None) if sig is not None: signal.signal(sig, signal.SIG_DFL) if start_new_session: os.setsid() try: if env is None: os.execvp(executable, args) else: # Python 3.6 started testing for # bytes values in the env; it also # started encoding strs using # fsencode and using a lower-level # API that takes a list of keys # and values. We don't have access # to that API, so we go the reverse direction. env = {os.fsdecode(k) if isinstance(k, bytes) else k: os.fsdecode(v) if isinstance(v, bytes) else v for k, v in env.items()} os.execvpe(executable, args, env) except OSError as e: e._failed_exec = True raise except: exc_type, exc_value, tb = sys.exc_info() # Save the traceback and attach it to the exception object exc_lines = traceback.format_exception(exc_type, exc_value, tb) exc_value.child_traceback = ''.join(exc_lines) os.write(errpipe_write, pickle.dumps(exc_value)) finally: # Make sure that the process exits no matter what. # The return code does not matter much as it won't be # reported to the application os._exit(1) # Parent self._child_created = True if gc_was_enabled: gc.enable() finally: # be sure the FD is closed no matter what os.close(errpipe_write) # self._devnull is not always defined. devnull_fd = getattr(self, '_devnull', None) if p2cread != -1 and p2cwrite != -1 and p2cread != devnull_fd: os.close(p2cread) if c2pwrite != -1 and c2pread != -1 and c2pwrite != devnull_fd: os.close(c2pwrite) if errwrite != -1 and errread != -1 and errwrite != devnull_fd: os.close(errwrite) if devnull_fd is not None: os.close(devnull_fd) # Prevent a double close of these fds from __init__ on error. self._closed_child_pipe_fds = True # Wait for exec to fail or succeed; possibly raising exception errpipe_read = FileObject(errpipe_read, 'rb') data = errpipe_read.read() finally: try: if hasattr(errpipe_read, 'close'): errpipe_read.close() else: os.close(errpipe_read) except OSError: # Especially on PyPy, we sometimes see the above # `os.close(errpipe_read)` raise an OSError. # It's not entirely clear why, but it happens in # InterprocessSignalTests.test_main sometimes, which must mean # we have some sort of race condition. pass finally: errpipe_read = -1 if data != b"": self.wait() child_exception = pickle.loads(data) for fd in (p2cwrite, c2pread, errread): if fd is not None and fd != -1: os.close(fd) if isinstance(child_exception, OSError): child_exception.filename = executable if hasattr(child_exception, '_failed_chdir'): child_exception.filename = cwd if getattr(child_exception, '_failed_chuser', False): child_exception.filename = None > raise child_exception E OSError: [Errno 8] Exec format error: 'locust' /usr/lib/python3/dist-packages/gevent/subprocess.py:1838: OSError __________ DistributedIntegrationTests.test_processes_separate_worker __________ self = @unittest.skipIf(os.name == "nt", reason="--processes doesnt work on windows") def test_processes_separate_worker(self): with mock_locustfile() as mocked: master_proc = subprocess.Popen( f"locust -f {mocked.file_path} --master --headless --run-time 1 --exit-code-on-error 0 --expect-workers-max-wait 2", shell=True, stdout=PIPE, stderr=PIPE, text=True, ) worker_parent_proc = subprocess.Popen( f"locust -f {mocked.file_path} --processes 4 --worker", shell=True, stdout=PIPE, stderr=PIPE, text=True, ) try: _, worker_stderr = worker_parent_proc.communicate(timeout=9) except Exception: master_proc.kill() worker_parent_proc.kill() _, worker_stderr = worker_parent_proc.communicate() _, master_stderr = master_proc.communicate() assert False, f"worker never finished: {worker_stderr}" try: _, master_stderr = master_proc.communicate(timeout=9) except Exception: master_proc.kill() worker_parent_proc.kill() _, worker_stderr = worker_parent_proc.communicate() _, master_stderr = master_proc.communicate() assert False, f"master never finished: {master_stderr}" _, worker_stderr = worker_parent_proc.communicate() _, master_stderr = master_proc.communicate() self.assertNotIn("Traceback", worker_stderr) self.assertNotIn("Traceback", master_stderr) self.assertNotIn("Gave up waiting for workers to connect", master_stderr) > self.assertIn("(index 3) reported as ready", master_stderr) E AssertionError: '(index 3) reported as ready' not found in '/build/reproducible-path/locust-2.24.0/debian/locust: line 2: from: command not found\n/build/reproducible-path/locust-2.24.0/debian/locust: line 5: syntax error: unexpected end of file\n' locust/test/test_main.py:2058: AssertionError ______ DistributedIntegrationTests.test_processes_workers_quit_unexpected ______ self = @unittest.skipIf(os.name == "nt", reason="--processes doesnt work on windows") @unittest.skipIf(sys.platform == "darwin", reason="Flaky on macOS :-/") def test_processes_workers_quit_unexpected(self): content = """ from locust import runners, events, User, task import sys runners.HEARTBEAT_INTERVAL = 0.1 @events.test_start.add_listener def on_test_start(environment, **_kwargs): if isinstance(environment.runner, runners.WorkerRunner): sys.exit(42) class AnyUser(User): @task def mytask(self): pass """ with mock_locustfile(content=content) as mocked: > worker_proc = subprocess.Popen( ["locust", "-f", mocked.file_path, "--processes", "2", "--worker"], stdout=PIPE, stderr=PIPE, text=True, ) locust/test/test_main.py:2202: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3/dist-packages/gevent/subprocess.py:808: in __init__ self._execute_child(args, executable, preexec_fn, close_fds, _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = args = ['locust', '-f', '/build/reproducible-path/locust-2.24.0/locust/test/mock_locustfile_1715255814_3232915_86946.py', '--processes', '2', '--worker'] executable = 'locust', preexec_fn = None, close_fds = True, pass_fds = () cwd = None, env = None, universal_newlines = None, startupinfo = None creationflags = 0, shell = False, p2cread = -1, p2cwrite = -1, c2pread = 11 c2pwrite = 81, errread = 82, errwrite = 83, restore_signals = True, gid = None gids = None, uid = None, umask = -1, start_new_session = False process_group = None def _execute_child(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, universal_newlines, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, restore_signals, gid, gids, uid, umask, start_new_session, process_group): """Execute program (POSIX version)""" if isinstance(args, (str, bytes)): args = [args] elif isinstance(args, PathLike): if shell: raise TypeError('path-like args is not allowed when ' 'shell is true') args = [fsencode(args)] # os.PathLike -> [str] else: args = list(args) if shell: # On Android the default shell is at '/system/bin/sh'. unix_shell = ( '/system/bin/sh' if hasattr(sys, 'getandroidapilevel') else '/bin/sh' ) args = [unix_shell, "-c"] + args if executable: args[0] = executable if executable is None: executable = args[0] self._loop.install_sigchld() # For transferring possible exec failure from child to parent # The first char specifies the exception type: 0 means # OSError, 1 means some other error. errpipe_read, errpipe_write = self.pipe_cloexec() # errpipe_write must not be in the standard io 0, 1, or 2 fd range. low_fds_to_close = [] while errpipe_write < 3: low_fds_to_close.append(errpipe_write) errpipe_write = os.dup(errpipe_write) for low_fd in low_fds_to_close: os.close(low_fd) try: try: gc_was_enabled = gc.isenabled() # Disable gc to avoid bug where gc -> file_dealloc -> # write to stderr -> hang. http://bugs.python.org/issue1336 gc.disable() try: self.pid = fork_and_watch(self._on_child, self._loop, True, fork) except: if gc_was_enabled: gc.enable() raise if self.pid == 0: # Child # In various places on the child side of things, we catch OSError # and add attributes to it that detail where in the process we failed; # like all exceptions until we have exec'd, this exception is pickled # and sent to the parent to raise in the calling process. # The parent uses this to decide how to treat that exception, # adjusting certain information about it as needed. # # Python 3.11.8 --- yes, a minor patch release --- stopped # letting the 'filename' parameter get set in the resulting # exception for many cases. We're not quite interpreting this # the same way the stdlib is, I'm sure, but this makes the stdlib # tests pass. # XXX: Technically we're doing a lot of stuff here that # may not be safe to do before a exec(), depending on the OS. # CPython 3 goes to great lengths to precompute a lot # of this info before the fork and pass it all to C functions that # try hard not to call things like malloc(). (Of course, # CPython 2 pretty much did what we're doing.) try: # Close parent's pipe ends if p2cwrite != -1: os.close(p2cwrite) if c2pread != -1: os.close(c2pread) if errread != -1: os.close(errread) os.close(errpipe_read) # When duping fds, if there arises a situation # where one of the fds is either 0, 1 or 2, it # is possible that it is overwritten (#12607). if c2pwrite == 0: c2pwrite = os.dup(c2pwrite) _set_inheritable(c2pwrite, False) while errwrite in (0, 1): errwrite = os.dup(errwrite) _set_inheritable(errwrite, False) # Dup fds for child def _dup2(existing, desired): # dup2() removes the CLOEXEC flag but # we must do it ourselves if dup2() # would be a no-op (issue #10806). if existing == desired: self._set_cloexec_flag(existing, False) elif existing != -1: os.dup2(existing, desired) try: self._remove_nonblock_flag(desired) except OSError: # Ignore EBADF, it may not actually be # open yet. # Tested beginning in 3.7.0b3 test_subprocess.py pass _dup2(p2cread, 0) _dup2(c2pwrite, 1) _dup2(errwrite, 2) # Close pipe fds. Make sure we don't close the # same fd more than once, or standard fds. if not True: closed = set([None]) for fd in (p2cread, c2pwrite, errwrite): if fd not in closed and fd > 2: os.close(fd) closed.add(fd) # Python 3 (with a working set_inheritable): # We no longer manually close p2cread, # c2pwrite, and errwrite here as # _close_open_fds takes care when it is # not already non-inheritable. if cwd is not None: try: os.chdir(cwd) except OSError as e: e._failed_chdir = True raise # Python 3.9 if umask >= 0: os.umask(umask) # XXX: CPython does _Py_RestoreSignals here. # Then setsid() based on ??? try: if gids: os.setgroups(gids) if gid: os.setregid(gid, gid) if uid: os.setreuid(uid, uid) if process_group is not None: os.setpgid(0, process_group) except OSError as e: e._failed_chuser = True raise if preexec_fn: preexec_fn() # Close all other fds, if asked for. This must be done # after preexec_fn runs. if close_fds: fds_to_keep = set(pass_fds) fds_to_keep.add(errpipe_write) self._close_fds(fds_to_keep, errpipe_write) if restore_signals: # restore the documented signals back to sig_dfl; # not all will be defined on every platform for sig in 'SIGPIPE', 'SIGXFZ', 'SIGXFSZ': sig = getattr(signal, sig, None) if sig is not None: signal.signal(sig, signal.SIG_DFL) if start_new_session: os.setsid() try: if env is None: os.execvp(executable, args) else: # Python 3.6 started testing for # bytes values in the env; it also # started encoding strs using # fsencode and using a lower-level # API that takes a list of keys # and values. We don't have access # to that API, so we go the reverse direction. env = {os.fsdecode(k) if isinstance(k, bytes) else k: os.fsdecode(v) if isinstance(v, bytes) else v for k, v in env.items()} os.execvpe(executable, args, env) except OSError as e: e._failed_exec = True raise except: exc_type, exc_value, tb = sys.exc_info() # Save the traceback and attach it to the exception object exc_lines = traceback.format_exception(exc_type, exc_value, tb) exc_value.child_traceback = ''.join(exc_lines) os.write(errpipe_write, pickle.dumps(exc_value)) finally: # Make sure that the process exits no matter what. # The return code does not matter much as it won't be # reported to the application os._exit(1) # Parent self._child_created = True if gc_was_enabled: gc.enable() finally: # be sure the FD is closed no matter what os.close(errpipe_write) # self._devnull is not always defined. devnull_fd = getattr(self, '_devnull', None) if p2cread != -1 and p2cwrite != -1 and p2cread != devnull_fd: os.close(p2cread) if c2pwrite != -1 and c2pread != -1 and c2pwrite != devnull_fd: os.close(c2pwrite) if errwrite != -1 and errread != -1 and errwrite != devnull_fd: os.close(errwrite) if devnull_fd is not None: os.close(devnull_fd) # Prevent a double close of these fds from __init__ on error. self._closed_child_pipe_fds = True # Wait for exec to fail or succeed; possibly raising exception errpipe_read = FileObject(errpipe_read, 'rb') data = errpipe_read.read() finally: try: if hasattr(errpipe_read, 'close'): errpipe_read.close() else: os.close(errpipe_read) except OSError: # Especially on PyPy, we sometimes see the above # `os.close(errpipe_read)` raise an OSError. # It's not entirely clear why, but it happens in # InterprocessSignalTests.test_main sometimes, which must mean # we have some sort of race condition. pass finally: errpipe_read = -1 if data != b"": self.wait() child_exception = pickle.loads(data) for fd in (p2cwrite, c2pread, errread): if fd is not None and fd != -1: os.close(fd) if isinstance(child_exception, OSError): child_exception.filename = executable if hasattr(child_exception, '_failed_chdir'): child_exception.filename = cwd if getattr(child_exception, '_failed_chuser', False): child_exception.filename = None > raise child_exception E OSError: [Errno 8] Exec format error: 'locust' /usr/lib/python3/dist-packages/gevent/subprocess.py:1838: OSError _______________ DistributedIntegrationTests.test_worker_indexes ________________ self = def test_worker_indexes(self): content = """ from locust import HttpUser, task, between class AnyUser(HttpUser): host = "http://127.0.0.1:8089" wait_time = between(0, 0.1) @task def my_task(self): print("worker index:", self.environment.runner.worker_index) """ with mock_locustfile(content=content) as mocked: > master = subprocess.Popen( [ "locust", "-f", mocked.file_path, "--headless", "--master", "--expect-workers", "2", "-t", "5", "-u", "2", "-L", "DEBUG", ], stdout=PIPE, stderr=PIPE, text=True, ) locust/test/test_main.py:1900: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3/dist-packages/gevent/subprocess.py:808: in __init__ self._execute_child(args, executable, preexec_fn, close_fds, _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = args = ['locust', '-f', '/build/reproducible-path/locust-2.24.0/locust/test/mock_locustfile_1715255814_5301445_55711.py', '--headless', '--master', '--expect-workers', ...] executable = 'locust', preexec_fn = None, close_fds = True, pass_fds = () cwd = None, env = None, universal_newlines = None, startupinfo = None creationflags = 0, shell = False, p2cread = -1, p2cwrite = -1, c2pread = 11 c2pwrite = 81, errread = 82, errwrite = 83, restore_signals = True, gid = None gids = None, uid = None, umask = -1, start_new_session = False process_group = None def _execute_child(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, universal_newlines, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, restore_signals, gid, gids, uid, umask, start_new_session, process_group): """Execute program (POSIX version)""" if isinstance(args, (str, bytes)): args = [args] elif isinstance(args, PathLike): if shell: raise TypeError('path-like args is not allowed when ' 'shell is true') args = [fsencode(args)] # os.PathLike -> [str] else: args = list(args) if shell: # On Android the default shell is at '/system/bin/sh'. unix_shell = ( '/system/bin/sh' if hasattr(sys, 'getandroidapilevel') else '/bin/sh' ) args = [unix_shell, "-c"] + args if executable: args[0] = executable if executable is None: executable = args[0] self._loop.install_sigchld() # For transferring possible exec failure from child to parent # The first char specifies the exception type: 0 means # OSError, 1 means some other error. errpipe_read, errpipe_write = self.pipe_cloexec() # errpipe_write must not be in the standard io 0, 1, or 2 fd range. low_fds_to_close = [] while errpipe_write < 3: low_fds_to_close.append(errpipe_write) errpipe_write = os.dup(errpipe_write) for low_fd in low_fds_to_close: os.close(low_fd) try: try: gc_was_enabled = gc.isenabled() # Disable gc to avoid bug where gc -> file_dealloc -> # write to stderr -> hang. http://bugs.python.org/issue1336 gc.disable() try: self.pid = fork_and_watch(self._on_child, self._loop, True, fork) except: if gc_was_enabled: gc.enable() raise if self.pid == 0: # Child # In various places on the child side of things, we catch OSError # and add attributes to it that detail where in the process we failed; # like all exceptions until we have exec'd, this exception is pickled # and sent to the parent to raise in the calling process. # The parent uses this to decide how to treat that exception, # adjusting certain information about it as needed. # # Python 3.11.8 --- yes, a minor patch release --- stopped # letting the 'filename' parameter get set in the resulting # exception for many cases. We're not quite interpreting this # the same way the stdlib is, I'm sure, but this makes the stdlib # tests pass. # XXX: Technically we're doing a lot of stuff here that # may not be safe to do before a exec(), depending on the OS. # CPython 3 goes to great lengths to precompute a lot # of this info before the fork and pass it all to C functions that # try hard not to call things like malloc(). (Of course, # CPython 2 pretty much did what we're doing.) try: # Close parent's pipe ends if p2cwrite != -1: os.close(p2cwrite) if c2pread != -1: os.close(c2pread) if errread != -1: os.close(errread) os.close(errpipe_read) # When duping fds, if there arises a situation # where one of the fds is either 0, 1 or 2, it # is possible that it is overwritten (#12607). if c2pwrite == 0: c2pwrite = os.dup(c2pwrite) _set_inheritable(c2pwrite, False) while errwrite in (0, 1): errwrite = os.dup(errwrite) _set_inheritable(errwrite, False) # Dup fds for child def _dup2(existing, desired): # dup2() removes the CLOEXEC flag but # we must do it ourselves if dup2() # would be a no-op (issue #10806). if existing == desired: self._set_cloexec_flag(existing, False) elif existing != -1: os.dup2(existing, desired) try: self._remove_nonblock_flag(desired) except OSError: # Ignore EBADF, it may not actually be # open yet. # Tested beginning in 3.7.0b3 test_subprocess.py pass _dup2(p2cread, 0) _dup2(c2pwrite, 1) _dup2(errwrite, 2) # Close pipe fds. Make sure we don't close the # same fd more than once, or standard fds. if not True: closed = set([None]) for fd in (p2cread, c2pwrite, errwrite): if fd not in closed and fd > 2: os.close(fd) closed.add(fd) # Python 3 (with a working set_inheritable): # We no longer manually close p2cread, # c2pwrite, and errwrite here as # _close_open_fds takes care when it is # not already non-inheritable. if cwd is not None: try: os.chdir(cwd) except OSError as e: e._failed_chdir = True raise # Python 3.9 if umask >= 0: os.umask(umask) # XXX: CPython does _Py_RestoreSignals here. # Then setsid() based on ??? try: if gids: os.setgroups(gids) if gid: os.setregid(gid, gid) if uid: os.setreuid(uid, uid) if process_group is not None: os.setpgid(0, process_group) except OSError as e: e._failed_chuser = True raise if preexec_fn: preexec_fn() # Close all other fds, if asked for. This must be done # after preexec_fn runs. if close_fds: fds_to_keep = set(pass_fds) fds_to_keep.add(errpipe_write) self._close_fds(fds_to_keep, errpipe_write) if restore_signals: # restore the documented signals back to sig_dfl; # not all will be defined on every platform for sig in 'SIGPIPE', 'SIGXFZ', 'SIGXFSZ': sig = getattr(signal, sig, None) if sig is not None: signal.signal(sig, signal.SIG_DFL) if start_new_session: os.setsid() try: if env is None: os.execvp(executable, args) else: # Python 3.6 started testing for # bytes values in the env; it also # started encoding strs using # fsencode and using a lower-level # API that takes a list of keys # and values. We don't have access # to that API, so we go the reverse direction. env = {os.fsdecode(k) if isinstance(k, bytes) else k: os.fsdecode(v) if isinstance(v, bytes) else v for k, v in env.items()} os.execvpe(executable, args, env) except OSError as e: e._failed_exec = True raise except: exc_type, exc_value, tb = sys.exc_info() # Save the traceback and attach it to the exception object exc_lines = traceback.format_exception(exc_type, exc_value, tb) exc_value.child_traceback = ''.join(exc_lines) os.write(errpipe_write, pickle.dumps(exc_value)) finally: # Make sure that the process exits no matter what. # The return code does not matter much as it won't be # reported to the application os._exit(1) # Parent self._child_created = True if gc_was_enabled: gc.enable() finally: # be sure the FD is closed no matter what os.close(errpipe_write) # self._devnull is not always defined. devnull_fd = getattr(self, '_devnull', None) if p2cread != -1 and p2cwrite != -1 and p2cread != devnull_fd: os.close(p2cread) if c2pwrite != -1 and c2pread != -1 and c2pwrite != devnull_fd: os.close(c2pwrite) if errwrite != -1 and errread != -1 and errwrite != devnull_fd: os.close(errwrite) if devnull_fd is not None: os.close(devnull_fd) # Prevent a double close of these fds from __init__ on error. self._closed_child_pipe_fds = True # Wait for exec to fail or succeed; possibly raising exception errpipe_read = FileObject(errpipe_read, 'rb') data = errpipe_read.read() finally: try: if hasattr(errpipe_read, 'close'): errpipe_read.close() else: os.close(errpipe_read) except OSError: # Especially on PyPy, we sometimes see the above # `os.close(errpipe_read)` raise an OSError. # It's not entirely clear why, but it happens in # InterprocessSignalTests.test_main sometimes, which must mean # we have some sort of race condition. pass finally: errpipe_read = -1 if data != b"": self.wait() child_exception = pickle.loads(data) for fd in (p2cwrite, c2pread, errread): if fd is not None and fd != -1: os.close(fd) if isinstance(child_exception, OSError): child_exception.filename = executable if hasattr(child_exception, '_failed_chdir'): child_exception.filename = cwd if getattr(child_exception, '_failed_chuser', False): child_exception.filename = None > raise child_exception E OSError: [Errno 8] Exec format error: 'locust' /usr/lib/python3/dist-packages/gevent/subprocess.py:1838: OSError _____ DistributedIntegrationTests.test_workers_shut_down_if_master_is_gone _____ self = @unittest.skipIf(os.name == "nt", reason="--processes doesnt work on windows") def test_workers_shut_down_if_master_is_gone(self): content = """ from locust import HttpUser, task, constant, runners runners.MASTER_HEARTBEAT_TIMEOUT = 2 class AnyUser(HttpUser): host = "http://127.0.0.1:8089" wait_time = constant(1) @task def my_task(self): print("worker index:", self.environment.runner.worker_index) """ with mock_locustfile(content=content) as mocked: > master_proc = subprocess.Popen( [ "locust", "-f", mocked.file_path, "--master", "--headless", "--expect-workers", "2", ], stdout=PIPE, stderr=PIPE, text=True, ) locust/test/test_main.py:2115: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3/dist-packages/gevent/subprocess.py:808: in __init__ self._execute_child(args, executable, preexec_fn, close_fds, _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = args = ['locust', '-f', '/build/reproducible-path/locust-2.24.0/locust/test/mock_locustfile_1715255814_7341502_81094.py', '--master', '--headless', '--expect-workers', ...] executable = 'locust', preexec_fn = None, close_fds = True, pass_fds = () cwd = None, env = None, universal_newlines = None, startupinfo = None creationflags = 0, shell = False, p2cread = -1, p2cwrite = -1, c2pread = 11 c2pwrite = 81, errread = 82, errwrite = 83, restore_signals = True, gid = None gids = None, uid = None, umask = -1, start_new_session = False process_group = None def _execute_child(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, universal_newlines, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, restore_signals, gid, gids, uid, umask, start_new_session, process_group): """Execute program (POSIX version)""" if isinstance(args, (str, bytes)): args = [args] elif isinstance(args, PathLike): if shell: raise TypeError('path-like args is not allowed when ' 'shell is true') args = [fsencode(args)] # os.PathLike -> [str] else: args = list(args) if shell: # On Android the default shell is at '/system/bin/sh'. unix_shell = ( '/system/bin/sh' if hasattr(sys, 'getandroidapilevel') else '/bin/sh' ) args = [unix_shell, "-c"] + args if executable: args[0] = executable if executable is None: executable = args[0] self._loop.install_sigchld() # For transferring possible exec failure from child to parent # The first char specifies the exception type: 0 means # OSError, 1 means some other error. errpipe_read, errpipe_write = self.pipe_cloexec() # errpipe_write must not be in the standard io 0, 1, or 2 fd range. low_fds_to_close = [] while errpipe_write < 3: low_fds_to_close.append(errpipe_write) errpipe_write = os.dup(errpipe_write) for low_fd in low_fds_to_close: os.close(low_fd) try: try: gc_was_enabled = gc.isenabled() # Disable gc to avoid bug where gc -> file_dealloc -> # write to stderr -> hang. http://bugs.python.org/issue1336 gc.disable() try: self.pid = fork_and_watch(self._on_child, self._loop, True, fork) except: if gc_was_enabled: gc.enable() raise if self.pid == 0: # Child # In various places on the child side of things, we catch OSError # and add attributes to it that detail where in the process we failed; # like all exceptions until we have exec'd, this exception is pickled # and sent to the parent to raise in the calling process. # The parent uses this to decide how to treat that exception, # adjusting certain information about it as needed. # # Python 3.11.8 --- yes, a minor patch release --- stopped # letting the 'filename' parameter get set in the resulting # exception for many cases. We're not quite interpreting this # the same way the stdlib is, I'm sure, but this makes the stdlib # tests pass. # XXX: Technically we're doing a lot of stuff here that # may not be safe to do before a exec(), depending on the OS. # CPython 3 goes to great lengths to precompute a lot # of this info before the fork and pass it all to C functions that # try hard not to call things like malloc(). (Of course, # CPython 2 pretty much did what we're doing.) try: # Close parent's pipe ends if p2cwrite != -1: os.close(p2cwrite) if c2pread != -1: os.close(c2pread) if errread != -1: os.close(errread) os.close(errpipe_read) # When duping fds, if there arises a situation # where one of the fds is either 0, 1 or 2, it # is possible that it is overwritten (#12607). if c2pwrite == 0: c2pwrite = os.dup(c2pwrite) _set_inheritable(c2pwrite, False) while errwrite in (0, 1): errwrite = os.dup(errwrite) _set_inheritable(errwrite, False) # Dup fds for child def _dup2(existing, desired): # dup2() removes the CLOEXEC flag but # we must do it ourselves if dup2() # would be a no-op (issue #10806). if existing == desired: self._set_cloexec_flag(existing, False) elif existing != -1: os.dup2(existing, desired) try: self._remove_nonblock_flag(desired) except OSError: # Ignore EBADF, it may not actually be # open yet. # Tested beginning in 3.7.0b3 test_subprocess.py pass _dup2(p2cread, 0) _dup2(c2pwrite, 1) _dup2(errwrite, 2) # Close pipe fds. Make sure we don't close the # same fd more than once, or standard fds. if not True: closed = set([None]) for fd in (p2cread, c2pwrite, errwrite): if fd not in closed and fd > 2: os.close(fd) closed.add(fd) # Python 3 (with a working set_inheritable): # We no longer manually close p2cread, # c2pwrite, and errwrite here as # _close_open_fds takes care when it is # not already non-inheritable. if cwd is not None: try: os.chdir(cwd) except OSError as e: e._failed_chdir = True raise # Python 3.9 if umask >= 0: os.umask(umask) # XXX: CPython does _Py_RestoreSignals here. # Then setsid() based on ??? try: if gids: os.setgroups(gids) if gid: os.setregid(gid, gid) if uid: os.setreuid(uid, uid) if process_group is not None: os.setpgid(0, process_group) except OSError as e: e._failed_chuser = True raise if preexec_fn: preexec_fn() # Close all other fds, if asked for. This must be done # after preexec_fn runs. if close_fds: fds_to_keep = set(pass_fds) fds_to_keep.add(errpipe_write) self._close_fds(fds_to_keep, errpipe_write) if restore_signals: # restore the documented signals back to sig_dfl; # not all will be defined on every platform for sig in 'SIGPIPE', 'SIGXFZ', 'SIGXFSZ': sig = getattr(signal, sig, None) if sig is not None: signal.signal(sig, signal.SIG_DFL) if start_new_session: os.setsid() try: if env is None: os.execvp(executable, args) else: # Python 3.6 started testing for # bytes values in the env; it also # started encoding strs using # fsencode and using a lower-level # API that takes a list of keys # and values. We don't have access # to that API, so we go the reverse direction. env = {os.fsdecode(k) if isinstance(k, bytes) else k: os.fsdecode(v) if isinstance(v, bytes) else v for k, v in env.items()} os.execvpe(executable, args, env) except OSError as e: e._failed_exec = True raise except: exc_type, exc_value, tb = sys.exc_info() # Save the traceback and attach it to the exception object exc_lines = traceback.format_exception(exc_type, exc_value, tb) exc_value.child_traceback = ''.join(exc_lines) os.write(errpipe_write, pickle.dumps(exc_value)) finally: # Make sure that the process exits no matter what. # The return code does not matter much as it won't be # reported to the application os._exit(1) # Parent self._child_created = True if gc_was_enabled: gc.enable() finally: # be sure the FD is closed no matter what os.close(errpipe_write) # self._devnull is not always defined. devnull_fd = getattr(self, '_devnull', None) if p2cread != -1 and p2cwrite != -1 and p2cread != devnull_fd: os.close(p2cread) if c2pwrite != -1 and c2pread != -1 and c2pwrite != devnull_fd: os.close(c2pwrite) if errwrite != -1 and errread != -1 and errwrite != devnull_fd: os.close(errwrite) if devnull_fd is not None: os.close(devnull_fd) # Prevent a double close of these fds from __init__ on error. self._closed_child_pipe_fds = True # Wait for exec to fail or succeed; possibly raising exception errpipe_read = FileObject(errpipe_read, 'rb') data = errpipe_read.read() finally: try: if hasattr(errpipe_read, 'close'): errpipe_read.close() else: os.close(errpipe_read) except OSError: # Especially on PyPy, we sometimes see the above # `os.close(errpipe_read)` raise an OSError. # It's not entirely clear why, but it happens in # InterprocessSignalTests.test_main sometimes, which must mean # we have some sort of race condition. pass finally: errpipe_read = -1 if data != b"": self.wait() child_exception = pickle.loads(data) for fd in (p2cwrite, c2pread, errread): if fd is not None and fd != -1: os.close(fd) if isinstance(child_exception, OSError): child_exception.filename = executable if hasattr(child_exception, '_failed_chdir'): child_exception.filename = cwd if getattr(child_exception, '_failed_chuser', False): child_exception.filename = None > raise child_exception E OSError: [Errno 8] Exec format error: 'locust' /usr/lib/python3/dist-packages/gevent/subprocess.py:1838: OSError ______________________ TestLocustRunner.test_cpu_warning _______________________ self = def test_cpu_warning(self): _monitor_interval = runners.CPU_MONITOR_INTERVAL runners.CPU_MONITOR_INTERVAL = 2.0 try: class CpuUser(User): wait_time = constant(0.001) @task def cpu_task(self): for i in range(1000000): _ = 3 / 2 environment = Environment(user_classes=[CpuUser]) environment._cpu_warning_event_triggered = False def cpu_warning(environment, cpu_usage, **kwargs): environment._cpu_warning_event_triggered = True environment._cpu_usage = cpu_usage environment.events.cpu_warning.add_listener(cpu_warning) runner = LocalRunner(environment) self.assertFalse(runner.cpu_warning_emitted) runner.spawn_users({CpuUser.__name__: 1}, wait=False) sleep(2.5) > self.assertTrue(environment._cpu_warning_event_triggered) E AssertionError: False is not true locust/test/test_runners.py:172: AssertionError _______________ TestLocustRunner.test_stop_users_with_spawn_rate _______________ self = def test_stop_users_with_spawn_rate(self): """ The spawn rate does not have an effect on the rate at which the users are stopped. It is expected that the excess users will be stopped as soon as possible in parallel (while respecting the stop_timeout). """ class MyUser(User): wait_time = constant(1) @task def my_task(self): pass environment = Environment(user_classes=[MyUser]) runner = LocalRunner(environment) # Start load test, wait for users to start, then trigger ramp down ts = time.time() runner.start(10, 10, wait=False) runner.spawning_greenlet.join() delta = time.time() - ts self.assertTrue( 0 <= delta <= 0.05, f"Expected user count to increase to 10 instantaneously, instead it took {delta:f}" ) self.assertTrue( runner.user_count == 10, "User count has not decreased correctly to 2, it is : %i" % runner.user_count ) ts = time.time() runner.start(2, 4, wait=False) runner.spawning_greenlet.join() delta = time.time() - ts > self.assertTrue(0 <= delta <= 1.05, f"Expected user count to decrease to 2 in 1s, instead it took {delta:f}") E AssertionError: False is not true : Expected user count to decrease to 2 in 1s, instead it took 1.064026 locust/test/test_runners.py:492: AssertionError ------------------------------ Captured log call ------------------------------- INFO locust.runners:runners.py:499 Ramping to 10 users at a rate of 10.00 per second INFO locust.runners:runners.py:537 All users spawned: {"MyUser": 10} (10 total users) INFO locust.runners:runners.py:499 Ramping to 2 users at a rate of 4.00 per second INFO locust.runners:runners.py:537 All users spawned: {"MyUser": 2} (2 total users) ________ TestMasterRunner.test_attributes_populated_when_calling_start _________ self = def test_attributes_populated_when_calling_start(self): class MyUser1(User): @task def my_task(self): pass class MyUser2(User): @task def my_task(self): pass with mock.patch("locust.rpc.rpc.Server", mocked_rpc()) as server: master = self.get_runner(user_classes=[MyUser1, MyUser2]) server.mocked_send(Message("client_ready", __version__, "fake_client1")) master.start(7, 7) > self.assertEqual({"MyUser1": 4, "MyUser2": 3}, master.target_user_classes_count) E AssertionError: {'MyUser1': 4, 'MyUser2': 3} != {} E - {'MyUser1': 4, 'MyUser2': 3} E + {} locust/test/test_runners.py:3033: AssertionError ------------------------------ Captured log call ------------------------------- ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (fake_client1). That's not going to work. WARNING locust.runners:runners.py:743 You can't start a distributed test before at least one worker processes has connected ________________ TestMasterRunner.test_custom_shape_scale_down _________________ self = def test_custom_shape_scale_down(self): class MyUser(User): @task def my_task(self): pass class TestShape(LoadTestShape): def tick(self): run_time = self.get_run_time() if run_time < 2: return 5, 5 elif run_time < 4: return 1, 5 else: return None self.environment.shape_class = TestShape() with mock.patch("locust.rpc.rpc.Server", mocked_rpc()) as server: master = self.get_runner(user_classes=[MyUser]) for i in range(5): server.mocked_send(Message("client_ready", __version__, "fake_client%i" % i)) # Start the shape_worker self.environment.shape_class.reset_time() master.start_shape() sleep(0.5) # Wait for shape_worker to update user_count num_users = sum( sum(msg.data["user_classes_count"].values()) for _, msg in server.outbox if msg.type != "ack" ) > self.assertEqual( 5, num_users, "Total number of users in first stage of shape test is not 5: %i" % num_users ) E AssertionError: 5 != 0 : Total number of users in first stage of shape test is not 5: 0 locust/test/test_runners.py:2907: AssertionError ------------------------------ Captured log call ------------------------------- ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (fake_client0). That's not going to work. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (fake_client1). That's not going to work. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (fake_client2). That's not going to work. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (fake_client3). That's not going to work. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (fake_client4). That's not going to work. INFO locust.runners:runners.py:329 Shape test starting. INFO locust.runners:runners.py:337 Shape worker starting INFO locust.runners:runners.py:356 Shape test updating to 5 users at 5.00 spawn rate WARNING locust.runners:runners.py:743 You can't start a distributed test before at least one worker processes has connected ______________ TestMasterRunner.test_custom_shape_scale_interval _______________ self = def test_custom_shape_scale_interval(self): class MyUser(User): @task def my_task(self): pass class TestShape(LoadTestShape): def __init__(self): super().__init__() self._users_num = [1, 1, 1, 2, 2, 3, 3, 3, 4] self._index = 0 def tick(self): if self._index >= len(self._users_num): return None users_num = self._users_num[self._index] self._index += 1 return users_num, users_num self.environment.shape_class = TestShape() with mock.patch("locust.rpc.rpc.Server", mocked_rpc()) as server: master = self.get_runner(user_classes=[MyUser]) for i in range(5): server.mocked_send(Message("client_ready", __version__, "fake_client%i" % i)) # Start the shape_worker self.environment.shape_class.reset_time() master.start_shape() # Wait for shape_worker to update user_count sleep(0.5) num_users = sum( sum(msg.data["user_classes_count"].values()) for _, msg in server.outbox if msg.type != "ack" ) > self.assertEqual( 1, num_users, "Total number of users in first stage of shape test is not 1: %i" % num_users ) E AssertionError: 1 != 0 : Total number of users in first stage of shape test is not 1: 0 locust/test/test_runners.py:2800: AssertionError ------------------------------ Captured log call ------------------------------- ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (fake_client0). That's not going to work. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (fake_client1). That's not going to work. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (fake_client2). That's not going to work. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (fake_client3). That's not going to work. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (fake_client4). That's not going to work. INFO locust.runners:runners.py:329 Shape test starting. INFO locust.runners:runners.py:337 Shape worker starting INFO locust.runners:runners.py:356 Shape test updating to 1 users at 1.00 spawn rate WARNING locust.runners:runners.py:743 You can't start a distributed test before at least one worker processes has connected _________________ TestMasterRunner.test_custom_shape_scale_up __________________ self = def test_custom_shape_scale_up(self): class MyUser(User): @task def my_task(self): pass class TestShape(LoadTestShape): def tick(self): run_time = self.get_run_time() if run_time < 2: return 1, 1 elif run_time < 4: return 2, 2 else: return None self.environment.shape_class = TestShape() with mock.patch("locust.rpc.rpc.Server", mocked_rpc()) as server: master = self.get_runner(user_classes=[MyUser]) for i in range(5): server.mocked_send(Message("client_ready", __version__, "fake_client%i" % i)) # Start the shape_worker self.environment.shape_class.reset_time() master.start_shape() sleep(0.5) # Wait for shape_worker to update user_count num_users = sum( sum(msg.data["user_classes_count"].values()) for _, msg in server.outbox if msg.type != "ack" ) > self.assertEqual( 1, num_users, "Total number of users in first stage of shape test is not 1: %i" % num_users ) E AssertionError: 1 != 0 : Total number of users in first stage of shape test is not 1: 0 locust/test/test_runners.py:2858: AssertionError ------------------------------ Captured log call ------------------------------- ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (fake_client0). That's not going to work. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (fake_client1). That's not going to work. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (fake_client2). That's not going to work. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (fake_client3). That's not going to work. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (fake_client4). That's not going to work. INFO locust.runners:runners.py:329 Shape test starting. INFO locust.runners:runners.py:337 Shape worker starting INFO locust.runners:runners.py:356 Shape test updating to 1 users at 1.00 spawn rate WARNING locust.runners:runners.py:743 You can't start a distributed test before at least one worker processes has connected _____________ TestMasterRunner.test_last_worker_missing_stops_test _____________ self = @mock.patch("locust.runners.HEARTBEAT_INTERVAL", new=0.1) def test_last_worker_missing_stops_test(self): class TestUser(User): @task def my_task(self): gevent.sleep(600) with mock.patch("locust.rpc.rpc.Server", mocked_rpc()) as server, patch_env( "LOCUST_WAIT_FOR_WORKERS_REPORT_AFTER_RAMP_UP", "0.1" ): master = self.get_runner(user_classes=[TestUser]) server.mocked_send(Message("client_ready", __version__, "fake_client1")) server.mocked_send(Message("client_ready", __version__, "fake_client2")) server.mocked_send(Message("client_ready", __version__, "fake_client3")) master.start(3, 3) server.mocked_send(Message("spawning", None, "fake_client1")) server.mocked_send(Message("spawning", None, "fake_client2")) server.mocked_send(Message("spawning", None, "fake_client3")) sleep(0.2) server.mocked_send( Message( "heartbeat", {"state": STATE_RUNNING, "current_cpu_usage": 50, "current_memory_usage": 200, "count": 1}, "fake_client1", ) ) server.mocked_send( Message( "heartbeat", {"state": STATE_RUNNING, "current_cpu_usage": 50, "current_memory_usage": 200, "count": 1}, "fake_client2", ) ) server.mocked_send( Message( "heartbeat", {"state": STATE_RUNNING, "current_cpu_usage": 50, "current_memory_usage": 200, "count": 1}, "fake_client3", ) ) sleep(0.2) self.assertEqual(0, len(master.clients.missing)) > self.assertEqual(3, master.worker_count) E AssertionError: 3 != 0 locust/test/test_runners.py:2236: AssertionError ------------------------------ Captured log call ------------------------------- ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (fake_client1). That's not going to work. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (fake_client2). That's not going to work. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (fake_client3). That's not going to work. WARNING locust.runners:runners.py:743 You can't start a distributed test before at least one worker processes has connected WARNING locust.runners:runners.py:1115 Got spawning message from unknown worker fake_client1. Asking worker to quit. WARNING locust.runners:runners.py:1115 Got spawning message from unknown worker fake_client2. Asking worker to quit. WARNING locust.runners:runners.py:1115 Got spawning message from unknown worker fake_client3. Asking worker to quit. ____________ TestMasterRunner.test_last_worker_quitting_stops_test _____________ self = def test_last_worker_quitting_stops_test(self): class TestUser(User): @task def my_task(self): gevent.sleep(600) with mock.patch("locust.rpc.rpc.Server", mocked_rpc()) as server, patch_env( "LOCUST_WAIT_FOR_WORKERS_REPORT_AFTER_RAMP_UP", "0.1" ): master = self.get_runner(user_classes=[TestUser]) server.mocked_send(Message("client_ready", __version__, "fake_client1")) server.mocked_send(Message("client_ready", __version__, "fake_client2")) master.start(1, 2) server.mocked_send(Message("spawning", None, "fake_client1")) server.mocked_send(Message("spawning", None, "fake_client2")) server.mocked_send(Message("quit", None, "fake_client1")) sleep(0.1) > self.assertEqual(1, len(master.clients.all)) E AssertionError: 1 != 0 locust/test/test_runners.py:2183: AssertionError ------------------------------ Captured log call ------------------------------- ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (fake_client1). That's not going to work. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (fake_client2). That's not going to work. WARNING locust.runners:runners.py:743 You can't start a distributed test before at least one worker processes has connected WARNING locust.runners:runners.py:1115 Got spawning message from unknown worker fake_client1. Asking worker to quit. WARNING locust.runners:runners.py:1115 Got spawning message from unknown worker fake_client2. Asking worker to quit. INFO locust.runners:runners.py:356 Shape test updating to 2 users at 2.00 spawn rate WARNING locust.runners:runners.py:743 You can't start a distributed test before at least one worker processes has connected ___________ TestMasterRunner.test_master_discard_first_client_ready ____________ self = def test_master_discard_first_client_ready(self): with mock.patch("locust.rpc.rpc.Server", mocked_rpc()) as server: server.mocked_send(Message("client_ready", __version__, "dummy_client")) # discard first client_ready msg server.queue.get() master = self.get_runner() server.mocked_send(Message("client_ready", __version__, "dummy_client")) > self.assertEqual(1, len(master.clients)) E AssertionError: 1 != 0 locust/test/test_runners.py:3148: AssertionError ------------------------------ Captured log call ------------------------------- ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (dummy_client). That's not going to work. _________ TestMasterRunner.test_master_marks_downed_workers_as_missing _________ self = def test_master_marks_downed_workers_as_missing(self): with mock.patch("locust.rpc.rpc.Server", mocked_rpc()) as server: master = self.get_runner() server.mocked_send(Message("client_ready", __version__, "fake_client")) sleep(6) # print(master.clients['fake_client'].__dict__) > assert master.clients["fake_client"].state == STATE_MISSING locust/test/test_runners.py:2162: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = , k = 'fake_client' def __getitem__(self, k: str) -> WorkerNode: > return self._worker_nodes[k] E KeyError: 'fake_client' locust/runners.py:636: KeyError ------------------------------ Captured log call ------------------------------- ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (fake_client). That's not going to work. INFO locust.runners:runners.py:356 Shape test updating to 2 users at 2.00 spawn rate WARNING locust.runners:runners.py:743 You can't start a distributed test before at least one worker processes has connected INFO locust.runners:runners.py:342 Shape test stopping INFO locust.runners:runners.py:933 Worker 0 failed to send heartbeat, setting state to missing. INFO locust.runners:runners.py:933 Worker 1 failed to send heartbeat, setting state to missing. INFO locust.runners:runners.py:933 Worker 2 failed to send heartbeat, setting state to missing. INFO locust.runners:runners.py:933 Worker 3 failed to send heartbeat, setting state to missing. INFO locust.runners:runners.py:933 Worker 4 failed to send heartbeat, setting state to missing. INFO locust.runners:runners.py:941 The last worker went missing, stopping test. INFO locust.runners:runners.py:342 Shape test stopping INFO locust.runners:runners.py:356 Shape test updating to 3 users at 3.00 spawn rate WARNING locust.runners:runners.py:743 You can't start a distributed test before at least one worker processes has connected INFO locust.runners:runners.py:356 Shape test updating to 4 users at 4.00 spawn rate WARNING locust.runners:runners.py:743 You can't start a distributed test before at least one worker processes has connected ________________ TestMasterRunner.test_master_reset_connection _________________ self = def test_master_reset_connection(self): """Test that connection will be reset when network issues found""" with mock.patch("locust.runners.FALLBACK_INTERVAL", new=0.1): with mock.patch("locust.rpc.rpc.Server", mocked_rpc(raise_on_close=False)) as server: master = self.get_runner() self.assertEqual(0, len(master.clients)) server.mocked_send(Message("client_ready", NETWORK_BROKEN, "fake_client")) self.assertTrue(master.connection_broken) server.mocked_send(Message("client_ready", __version__, "fake_client")) sleep(1) self.assertFalse(master.connection_broken) > self.assertEqual(1, len(master.clients)) E AssertionError: 1 != 0 locust/test/test_runners.py:2998: AssertionError ------------------------------ Captured log call ------------------------------- INFO locust.runners:runners.py:342 Shape test stopping ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (fake_client). That's not going to work. INFO locust.runners:runners.py:959 Resetting RPC server and all worker connections. ________ TestMasterRunner.test_rebalance_locust_users_on_worker_connect ________ self = @mock.patch("locust.runners.HEARTBEAT_INTERVAL", new=600) def test_rebalance_locust_users_on_worker_connect(self): class TestUser(User): @task def my_task(self): pass with mock.patch("locust.rpc.rpc.Server", mocked_rpc()) as server: master = self.get_runner(user_classes=[TestUser]) server.mocked_send(Message("client_ready", __version__, "zeh_fake_client1")) > self.assertEqual(1, len(master.clients)) E AssertionError: 1 != 0 locust/test/test_runners.py:2511: AssertionError ------------------------------ Captured log call ------------------------------- ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (zeh_fake_client1). That's not going to work. ____________ TestMasterRunner.test_reset_connection_after_RPCError _____________ self = def test_reset_connection_after_RPCError(self): with mock.patch("locust.rpc.rpc.Server", mocked_rpc(raise_on_close=False)) as server: master = self.get_runner() server.mocked_send(Message("client_ready", __version__, "fake_client")) sleep(0.2) self.assertFalse(master.connection_broken) > self.assertEqual(1, len(master.clients)) E AssertionError: 1 != 0 locust/test/test_runners.py:3007: AssertionError ------------------------------ Captured log call ------------------------------- ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (fake_client). That's not going to work. ______________ TestMasterRunner.test_spawn_correct_worker_indexes ______________ self = def test_spawn_correct_worker_indexes(self): """ Tests that workers would receive a monotonic sequence of ordinal IDs. """ class TestUser(User): @task def my_task(self): pass with mock.patch("locust.rpc.rpc.Server", mocked_rpc()) as server: master = self.get_runner(user_classes=[TestUser]) USERS_COUNT = 5 for i in range(USERS_COUNT): server.mocked_send(Message("client_ready", __version__, "fake_client%i" % i)) master.start(USERS_COUNT, USERS_COUNT) > self.assertEqual(USERS_COUNT * 2, len(server.outbox)) E AssertionError: 10 != 0 locust/test/test_runners.py:2753: AssertionError ------------------------------ Captured log call ------------------------------- ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (fake_client0). That's not going to work. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (fake_client1). That's not going to work. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (fake_client2). That's not going to work. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (fake_client3). That's not going to work. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (fake_client4). That's not going to work. WARNING locust.runners:runners.py:743 You can't start a distributed test before at least one worker processes has connected ____________ TestMasterRunner.test_spawn_fewer_locusts_than_workers ____________ self = def test_spawn_fewer_locusts_than_workers(self): class TestUser(User): @task def my_task(self): pass with mock.patch("locust.rpc.rpc.Server", mocked_rpc()) as server: master = self.get_runner(user_classes=[TestUser]) for i in range(5): server.mocked_send(Message("client_ready", __version__, "fake_client%i" % i)) master.start(2, 2) > self.assertEqual(10, len(server.outbox)) E AssertionError: 10 != 0 locust/test/test_runners.py:2726: AssertionError ------------------------------ Captured log call ------------------------------- ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (fake_client0). That's not going to work. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (fake_client1). That's not going to work. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (fake_client2). That's not going to work. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (fake_client3). That's not going to work. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (fake_client4). That's not going to work. WARNING locust.runners:runners.py:743 You can't start a distributed test before at least one worker processes has connected __________________ TestMasterRunner.test_spawn_uneven_locusts __________________ self = def test_spawn_uneven_locusts(self): """ Tests that we can accurately spawn a certain number of locusts, even if it's not an even number of the connected workers """ class TestUser(User): @task def my_task(self): pass with mock.patch("locust.rpc.rpc.Server", mocked_rpc()) as server: master = self.get_runner(user_classes=[TestUser]) for i in range(5): server.mocked_send(Message("client_ready", __version__, "fake_client%i" % i)) master.start(7, 7) > self.assertEqual(10, len(server.outbox)) E AssertionError: 10 != 0 locust/test/test_runners.py:2705: AssertionError ------------------------------ Captured log call ------------------------------- ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (fake_client0). That's not going to work. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (fake_client1). That's not going to work. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (fake_client2). That's not going to work. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (fake_client3). That's not going to work. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (fake_client4). That's not going to work. WARNING locust.runners:runners.py:743 You can't start a distributed test before at least one worker processes has connected ______________________ TestMasterRunner.test_start_event _______________________ self = def test_start_event(self): """ Tests that test_start event is fired """ class TestUser(User): @task def my_task(self): pass with mock.patch("locust.rpc.rpc.Server", mocked_rpc()) as server: master = self.get_runner(user_classes=[TestUser]) run_count = [0] @self.environment.events.test_start.add_listener def on_test_start(*a, **kw): run_count[0] += 1 for i in range(5): server.mocked_send(Message("client_ready", __version__, "fake_client%i" % i)) master.start(7, 7) > self.assertEqual(10, len(server.outbox)) E AssertionError: 10 != 0 locust/test/test_runners.py:2580: AssertionError ------------------------------ Captured log call ------------------------------- ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (fake_client0). That's not going to work. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (fake_client1). That's not going to work. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (fake_client2). That's not going to work. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (fake_client3). That's not going to work. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (fake_client4). That's not going to work. WARNING locust.runners:runners.py:743 You can't start a distributed test before at least one worker processes has connected _______________________ TestMasterRunner.test_stop_event _______________________ self = def test_stop_event(self): """ Tests that test_stop event is fired """ class TestUser(User): @task def my_task(self): pass with mock.patch("locust.rpc.rpc.Server", mocked_rpc()) as server: master = self.get_runner(user_classes=[TestUser]) @self.environment.events.test_stopping.add_listener def on_test_stopping(*_, **__): self.runner_stopping = True @self.environment.events.test_stop.add_listener def on_test_stop(*_, **__): self.runner_stopped = True for i in range(5): server.mocked_send(Message("client_ready", __version__, "fake_client%i" % i)) master.start(7, 7) > self.assertEqual(10, len(server.outbox)) E AssertionError: 10 != 0 locust/test/test_runners.py:2619: AssertionError ------------------------------ Captured log call ------------------------------- ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (fake_client0). That's not going to work. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (fake_client1). That's not going to work. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (fake_client2). That's not going to work. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (fake_client3). That's not going to work. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (fake_client4). That's not going to work. WARNING locust.runners:runners.py:743 You can't start a distributed test before at least one worker processes has connected ____________________ TestMasterRunner.test_stop_event_quit _____________________ self = def test_stop_event_quit(self): """ Tests that test_stop event is fired when quit() is called directly """ class TestUser(User): @task def my_task(self): pass with mock.patch("locust.rpc.rpc.Server", mocked_rpc()) as server: master = self.get_runner(user_classes=[TestUser]) @self.environment.events.test_stopping.add_listener def on_test_stopping(*_, **__): self.runner_stopping = True @self.environment.events.test_stop.add_listener def on_test_stop(*_, **__): self.runner_stopped = True for i in range(5): server.mocked_send(Message("client_ready", __version__, "fake_client%i" % i)) master.start(7, 7) > self.assertEqual(10, len(server.outbox)) E AssertionError: 10 != 0 locust/test/test_runners.py:2658: AssertionError ------------------------------ Captured log call ------------------------------- ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (fake_client0). That's not going to work. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (fake_client1). That's not going to work. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (fake_client2). That's not going to work. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (fake_client3). That's not going to work. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (fake_client4). That's not going to work. WARNING locust.runners:runners.py:743 You can't start a distributed test before at least one worker processes has connected __________ TestMasterRunner.test_unknown_host_sends_message_to_master __________ self = def test_unknown_host_sends_message_to_master(self): """ Validate master ignores message that is sent from unknown host """ class TestUser(User): @task def my_task(self): pass with mock.patch("locust.rpc.rpc.Server", mocked_rpc()) as server: master = self.get_runner(user_classes=[TestUser]) server.mocked_send(Message("client_ready", __version__, "zeh_fake_client1")) > self.assertEqual(1, len(master.clients)) E AssertionError: 1 != 0 locust/test/test_runners.py:3217: AssertionError ------------------------------ Captured log call ------------------------------- ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (zeh_fake_client1). That's not going to work. _____________________ TestMasterRunner.test_worker_connect _____________________ self = def test_worker_connect(self): with mock.patch("locust.rpc.rpc.Server", mocked_rpc()) as server: master = self.get_runner() server.mocked_send(Message("client_ready", __version__, "zeh_fake_client1")) > self.assertEqual(1, len(master.clients)) E AssertionError: 1 != 0 locust/test/test_runners.py:2083: AssertionError ------------------------------ Captured log call ------------------------------- ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (zeh_fake_client1). That's not going to work. __________ TestMasterRunner.test_worker_connect_with_special_versions __________ self = def test_worker_connect_with_special_versions(self): with mock.patch("locust.rpc.rpc.Server", mocked_rpc()) as server: master = self.get_runner() server.mocked_send(Message("client_ready", None, "1.x_style_client_should_not_be_allowed")) self.assertEqual(1, len(self.mocked_log.error)) self.assertEqual(0, len(master.clients)) server.mocked_send(Message("client_ready", "abcd", "other_version_mismatch_should_just_give_a_warning")) self.assertEqual(1, len(self.mocked_log.warning)) self.assertEqual(1, len(master.clients)) server.mocked_send(Message("client_ready", -1, "version_check_bypass_should_not_warn")) self.assertEqual(1, len(self.mocked_log.warning)) self.assertEqual(2, len(master.clients)) server.mocked_send( Message("client_ready", __version__ + "1", "difference_in_patch_version_should_not_warn") ) self.assertEqual(3, len(master.clients)) > self.assertEqual(1, len(self.mocked_log.warning)) E AssertionError: 1 != 2 locust/test/test_runners.py:2111: AssertionError ------------------------------ Captured log call ------------------------------- ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (1.x_style_client_should_not_be_allowed). That's not going to work. WARNING locust.runners:runners.py:1017 A worker (other_version_mismatch_should_just_give_a_warning) running a different version (abcd) connected, master version is INFO locust.runners:runners.py:1028 Worker other_version_mismatch_should_just_give_a_warning (index 0) reported as ready. 1 workers connected. INFO locust.runners:runners.py:1028 Worker version_check_bypass_should_not_warn (index 1) reported as ready. 2 workers connected. WARNING locust.runners:runners.py:1017 A worker (difference_in_patch_version_should_not_warn) running a different version (1) connected, master version is INFO locust.runners:runners.py:1028 Worker difference_in_patch_version_should_not_warn (index 2) reported as ready. 3 workers connected. ______ TestMasterRunner.test_worker_missing_after_heartbeat_dead_interval ______ self = @mock.patch("locust.runners.HEARTBEAT_INTERVAL", new=0.1) @mock.patch("locust.runners.HEARTBEAT_DEAD_INTERNAL", new=-3) def test_worker_missing_after_heartbeat_dead_interval(self): class TestUser(User): @task def my_task(self): gevent.sleep(600) with mock.patch("locust.rpc.rpc.Server", mocked_rpc()) as server, patch_env( "LOCUST_WAIT_FOR_WORKERS_REPORT_AFTER_RAMP_UP", "0.1" ): master = self.get_runner(user_classes=[TestUser]) server.mocked_send(Message("client_ready", __version__, "fake_client1")) server.mocked_send(Message("client_ready", __version__, "fake_client2")) server.mocked_send(Message("client_ready", __version__, "fake_client3")) master.start(3, 3) server.mocked_send(Message("spawning", None, "fake_client1")) server.mocked_send(Message("spawning", None, "fake_client2")) server.mocked_send(Message("spawning", None, "fake_client3")) sleep(0.1) server.mocked_send( Message( "heartbeat", {"state": STATE_RUNNING, "current_cpu_usage": 50, "current_memory_usage": 200, "count": 1}, "fake_client1", ) ) server.mocked_send( Message( "heartbeat", {"state": STATE_RUNNING, "current_cpu_usage": 50, "current_memory_usage": 200, "count": 1}, "fake_client2", ) ) server.mocked_send( Message( "heartbeat", {"state": STATE_RUNNING, "current_cpu_usage": 50, "current_memory_usage": 200, "count": 1}, "fake_client3", ) ) sleep(0.1) # initially all workers are in active state self.assertEqual(0, len(master.clients.missing)) > self.assertEqual(3, master.worker_count) E AssertionError: 3 != 0 locust/test/test_runners.py:2308: AssertionError ------------------------------ Captured log call ------------------------------- ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (fake_client1). That's not going to work. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (fake_client2). That's not going to work. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (fake_client3). That's not going to work. WARNING locust.runners:runners.py:743 You can't start a distributed test before at least one worker processes has connected WARNING locust.runners:runners.py:1115 Got spawning message from unknown worker fake_client1. Asking worker to quit. WARNING locust.runners:runners.py:1115 Got spawning message from unknown worker fake_client2. Asking worker to quit. WARNING locust.runners:runners.py:1115 Got spawning message from unknown worker fake_client3. Asking worker to quit. ___________ TestMasterRunner.test_worker_sends_bad_message_to_master ___________ self = def test_worker_sends_bad_message_to_master(self): """ Validate master sends reconnect message to worker when it receives a bad message. """ class TestUser(User): @task def my_task(self): pass with mock.patch("locust.rpc.rpc.Server", mocked_rpc()) as server: master = self.get_runner(user_classes=[TestUser]) server.mocked_send(Message("client_ready", __version__, "zeh_fake_client1")) > self.assertEqual(1, len(master.clients)) E AssertionError: 1 != 0 locust/test/test_runners.py:3166: AssertionError ------------------------------ Captured log call ------------------------------- ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (zeh_fake_client1). That's not going to work. ______ TestMasterRunner.test_worker_sends_unrecognized_message_to_master _______ self = def test_worker_sends_unrecognized_message_to_master(self): """ Validate master ignores message from worker when it cannot parse adddress info. """ class TestUser(User): @task def my_task(self): pass with mock.patch("locust.rpc.rpc.Server", mocked_rpc()) as server: master = self.get_runner(user_classes=[TestUser]) server.mocked_send(Message("client_ready", __version__, "zeh_fake_client1")) > self.assertEqual(1, len(master.clients)) E AssertionError: 1 != 0 locust/test/test_runners.py:3194: AssertionError ------------------------------ Captured log call ------------------------------- ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (zeh_fake_client1). That's not going to work. _____________ TestStopTimeout.test_kill_locusts_with_stop_timeout ______________ self = def test_kill_locusts_with_stop_timeout(self): short_time = 0.05 class MyTaskSet(TaskSet): @task def my_task(self): MyTaskSet.state = "first" gevent.sleep(short_time) MyTaskSet.state = "second" # should only run when run time + stop_timeout is > short_time gevent.sleep(short_time) MyTaskSet.state = "third" # should only run when run time + stop_timeout is > short_time * 2 class MyTestUser(User): tasks = [MyTaskSet] environment = create_environment([MyTestUser], mocked_options()) runner = environment.create_local_runner() runner.start(1, 1) gevent.sleep(short_time / 2) runner.stop_users({MyTestUser.__name__: 1}) > self.assertEqual("first", MyTaskSet.state) E AssertionError: 'first' != 'third' E - first E + third locust/test/test_runners.py:4105: AssertionError ------------------------------ Captured log call ------------------------------- INFO locust.runners:runners.py:499 Ramping to 1 users at a rate of 1.00 per second INFO locust.runners:runners.py:537 All users spawned: {"MyTestUser": 1} (1 total users) INFO locust.runners:runners.py:141 Resetting stats ______________________ TestStopTimeout.test_stop_timeout _______________________ self = def test_stop_timeout(self): short_time = 0.05 class MyTaskSet(TaskSet): @task def my_task(self): MyTaskSet.state = "first" gevent.sleep(short_time) MyTaskSet.state = "second" # should only run when run time + stop_timeout is > short_time gevent.sleep(short_time) MyTaskSet.state = "third" # should only run when run time + stop_timeout is > short_time * 2 class MyTestUser(User): tasks = [MyTaskSet] environment = Environment(user_classes=[MyTestUser]) runner = environment.create_local_runner() runner.start(1, 1, wait=False) gevent.sleep(short_time / 2) runner.quit() > self.assertEqual("first", MyTaskSet.state) E AssertionError: 'first' != 'second' E - first E + second locust/test/test_runners.py:3944: AssertionError ------------------------------ Captured log call ------------------------------- INFO locust.runners:runners.py:499 Ramping to 1 users at a rate of 1.00 per second INFO locust.runners:runners.py:537 All users spawned: {"MyTestUser": 1} (1 total users) ______________ TestStopTimeout.test_stop_timeout_during_on_start _______________ self = def test_stop_timeout_during_on_start(self): short_time = 0.05 class MyTaskSet(TaskSet): finished_on_start = False my_task_run = False def on_start(self): gevent.sleep(short_time) MyTaskSet.finished_on_start = True @task def my_task(self): MyTaskSet.my_task_run = True class MyTestUser(User): tasks = [MyTaskSet] environment = create_environment([MyTestUser], mocked_options()) environment.stop_timeout = short_time runner = environment.create_local_runner() runner.start(1, 1) gevent.sleep(short_time / 2) runner.quit() self.assertTrue(MyTaskSet.finished_on_start) > self.assertFalse(MyTaskSet.my_task_run) E AssertionError: True is not false locust/test/test_runners.py:3996: AssertionError ------------------------------ Captured log call ------------------------------- INFO locust.runners:runners.py:499 Ramping to 1 users at a rate of 1.00 per second INFO locust.runners:runners.py:537 All users spawned: {"MyTestUser": 1} (1 total users) INFO locust.runners:runners.py:141 Resetting stats ______________ TestStopTimeout.test_stop_timeout_exit_during_wait ______________ self = def test_stop_timeout_exit_during_wait(self): short_time = 0.05 class MyTaskSet(TaskSet): @task def my_task(self): pass class MyTestUser(User): tasks = [MyTaskSet] wait_time = constant(1) environment = Environment(user_classes=[MyTestUser], stop_timeout=short_time) runner = environment.create_local_runner() runner.start(1, 1) gevent.sleep(short_time) # sleep to make sure locust has had time to start waiting timeout = gevent.Timeout(short_time) timeout.start() try: > runner.quit() locust/test/test_runners.py:4017: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ locust/runners.py:415: in quit self.stop() locust/runners.py:562: in stop super().stop() locust/runners.py:402: in stop self.stop_users(self.user_classes_count) locust/runners.py:284: in stop_users async_calls_to_stop.join() /usr/lib/python3/dist-packages/gevent/pool.py:430: in join result = self._empty_event.wait(timeout=timeout) src/gevent/event.py:163: in gevent._gevent_cevent.Event.wait ??? src/gevent/_abstract_linkable.py:521: in gevent._gevent_c_abstract_linkable.AbstractLinkable._wait ??? src/gevent/_abstract_linkable.py:487: in gevent._gevent_c_abstract_linkable.AbstractLinkable._wait_core ??? src/gevent/_abstract_linkable.py:496: in gevent._gevent_c_abstract_linkable.AbstractLinkable._wait_core ??? src/gevent/_abstract_linkable.py:490: in gevent._gevent_c_abstract_linkable.AbstractLinkable._wait_core ??? src/gevent/_abstract_linkable.py:442: in gevent._gevent_c_abstract_linkable.AbstractLinkable._AbstractLinkable__wait_to_be_notified ??? src/gevent/_abstract_linkable.py:451: in gevent._gevent_c_abstract_linkable.AbstractLinkable._switch_to_hub ??? src/gevent/_greenlet_primitives.py:61: in gevent._gevent_c_greenlet_primitives.SwitchOutGreenletWithLoop.switch ??? src/gevent/_greenlet_primitives.py:65: in gevent._gevent_c_greenlet_primitives.SwitchOutGreenletWithLoop.switch ??? _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ > ??? E gevent.timeout.Timeout: 0.05 seconds src/gevent/_gevent_c_greenlet_primitives.pxd:35: Timeout During handling of the above exception, another exception occurred: self = def test_stop_timeout_exit_during_wait(self): short_time = 0.05 class MyTaskSet(TaskSet): @task def my_task(self): pass class MyTestUser(User): tasks = [MyTaskSet] wait_time = constant(1) environment = Environment(user_classes=[MyTestUser], stop_timeout=short_time) runner = environment.create_local_runner() runner.start(1, 1) gevent.sleep(short_time) # sleep to make sure locust has had time to start waiting timeout = gevent.Timeout(short_time) timeout.start() try: runner.quit() runner.greenlet.join() except gevent.Timeout: > self.fail("Got Timeout exception. Waiting locusts should stop immediately, even when using stop_timeout.") E AssertionError: Got Timeout exception. Waiting locusts should stop immediately, even when using stop_timeout. locust/test/test_runners.py:4020: AssertionError ------------------------------ Captured log call ------------------------------- INFO locust.runners:runners.py:499 Ramping to 1 users at a rate of 1.00 per second INFO locust.runners:runners.py:537 All users spawned: {"MyTestUser": 1} (1 total users) ________ TestStopTimeout.test_stop_timeout_with_interrupt_no_reschedule ________ self = def test_stop_timeout_with_interrupt_no_reschedule(self): state = [0] class MySubTaskSet(TaskSet): @task def a_task(self): gevent.sleep(0.1) state[0] = 1 self.interrupt(reschedule=False) class MyTestUser(User): tasks = [MySubTaskSet] wait_time = constant(3) options = mocked_options() options.stop_timeout = 0.3 environment = create_environment([MyTestUser], options) runner = environment.create_local_runner() runner.start(1, 1, wait=True) gevent.sleep(0) timeout = gevent.Timeout(0.11) timeout.start() try: > runner.quit() locust/test/test_runners.py:4077: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ locust/runners.py:415: in quit self.stop() locust/runners.py:562: in stop super().stop() locust/runners.py:402: in stop self.stop_users(self.user_classes_count) locust/runners.py:286: in stop_users if not stop_group.join(timeout=self.environment.stop_timeout): /usr/lib/python3/dist-packages/gevent/pool.py:430: in join result = self._empty_event.wait(timeout=timeout) src/gevent/event.py:163: in gevent._gevent_cevent.Event.wait ??? src/gevent/_abstract_linkable.py:521: in gevent._gevent_c_abstract_linkable.AbstractLinkable._wait ??? src/gevent/_abstract_linkable.py:487: in gevent._gevent_c_abstract_linkable.AbstractLinkable._wait_core ??? src/gevent/_abstract_linkable.py:496: in gevent._gevent_c_abstract_linkable.AbstractLinkable._wait_core ??? src/gevent/_abstract_linkable.py:490: in gevent._gevent_c_abstract_linkable.AbstractLinkable._wait_core ??? src/gevent/_abstract_linkable.py:442: in gevent._gevent_c_abstract_linkable.AbstractLinkable._AbstractLinkable__wait_to_be_notified ??? src/gevent/_abstract_linkable.py:451: in gevent._gevent_c_abstract_linkable.AbstractLinkable._switch_to_hub ??? src/gevent/_greenlet_primitives.py:61: in gevent._gevent_c_greenlet_primitives.SwitchOutGreenletWithLoop.switch ??? src/gevent/_greenlet_primitives.py:65: in gevent._gevent_c_greenlet_primitives.SwitchOutGreenletWithLoop.switch ??? _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ > ??? E gevent.timeout.Timeout: 0.11 seconds src/gevent/_gevent_c_greenlet_primitives.pxd:35: Timeout During handling of the above exception, another exception occurred: self = def test_stop_timeout_with_interrupt_no_reschedule(self): state = [0] class MySubTaskSet(TaskSet): @task def a_task(self): gevent.sleep(0.1) state[0] = 1 self.interrupt(reschedule=False) class MyTestUser(User): tasks = [MySubTaskSet] wait_time = constant(3) options = mocked_options() options.stop_timeout = 0.3 environment = create_environment([MyTestUser], options) runner = environment.create_local_runner() runner.start(1, 1, wait=True) gevent.sleep(0) timeout = gevent.Timeout(0.11) timeout.start() try: runner.quit() runner.greenlet.join() except gevent.Timeout: > self.fail("Got Timeout exception. Interrupted locusts should exit immediately during stop_timeout.") E AssertionError: Got Timeout exception. Interrupted locusts should exit immediately during stop_timeout. locust/test/test_runners.py:4080: AssertionError ------------------------------ Captured log call ------------------------------- INFO locust.runners:runners.py:499 Ramping to 1 users at a rate of 1.00 per second _______________________ TestCsvStats.test_stats_history ________________________ self = def test_stats_history(self): env1 = Environment(events=locust.events, catch_exceptions=False) runner1 = env1.create_master_runner("127.0.0.1", 5558) env2 = Environment(events=locust.events, catch_exceptions=False) > runner2 = env2.create_worker_runner("127.0.0.1", 5558) locust/test/test_stats.py:589: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ locust/env.py:153: in create_worker_runner return self._create_runner( locust/env.py:115: in _create_runner self.runner = runner_class(self, *args, **kwargs) locust/runners.py:1216: in __init__ self.connect_to_master() locust/runners.py:1445: in connect_to_master self.connect_to_master() locust/runners.py:1445: in connect_to_master self.connect_to_master() locust/runners.py:1445: in connect_to_master self.connect_to_master() locust/runners.py:1445: in connect_to_master self.connect_to_master() locust/runners.py:1445: in connect_to_master self.connect_to_master() locust/runners.py:1445: in connect_to_master self.connect_to_master() locust/runners.py:1445: in connect_to_master self.connect_to_master() locust/runners.py:1445: in connect_to_master self.connect_to_master() locust/runners.py:1445: in connect_to_master self.connect_to_master() locust/runners.py:1445: in connect_to_master self.connect_to_master() locust/runners.py:1445: in connect_to_master self.connect_to_master() locust/runners.py:1445: in connect_to_master self.connect_to_master() locust/runners.py:1445: in connect_to_master self.connect_to_master() locust/runners.py:1445: in connect_to_master self.connect_to_master() locust/runners.py:1445: in connect_to_master self.connect_to_master() locust/runners.py:1445: in connect_to_master self.connect_to_master() locust/runners.py:1445: in connect_to_master self.connect_to_master() locust/runners.py:1445: in connect_to_master self.connect_to_master() locust/runners.py:1445: in connect_to_master self.connect_to_master() locust/runners.py:1445: in connect_to_master self.connect_to_master() locust/runners.py:1445: in connect_to_master self.connect_to_master() locust/runners.py:1445: in connect_to_master self.connect_to_master() locust/runners.py:1445: in connect_to_master self.connect_to_master() locust/runners.py:1445: in connect_to_master self.connect_to_master() locust/runners.py:1445: in connect_to_master self.connect_to_master() locust/runners.py:1445: in connect_to_master self.connect_to_master() locust/runners.py:1445: in connect_to_master self.connect_to_master() locust/runners.py:1445: in connect_to_master self.connect_to_master() locust/runners.py:1445: in connect_to_master self.connect_to_master() locust/runners.py:1445: in connect_to_master self.connect_to_master() locust/runners.py:1445: in connect_to_master self.connect_to_master() locust/runners.py:1445: in connect_to_master self.connect_to_master() locust/runners.py:1445: in connect_to_master self.connect_to_master() locust/runners.py:1445: in connect_to_master self.connect_to_master() locust/runners.py:1445: in connect_to_master self.connect_to_master() locust/runners.py:1445: in connect_to_master self.connect_to_master() locust/runners.py:1445: in connect_to_master self.connect_to_master() locust/runners.py:1445: in connect_to_master self.connect_to_master() locust/runners.py:1445: in connect_to_master self.connect_to_master() locust/runners.py:1445: in connect_to_master self.connect_to_master() locust/runners.py:1445: in connect_to_master self.connect_to_master() locust/runners.py:1445: in connect_to_master self.connect_to_master() locust/runners.py:1445: in connect_to_master self.connect_to_master() locust/runners.py:1445: in connect_to_master self.connect_to_master() locust/runners.py:1445: in connect_to_master self.connect_to_master() locust/runners.py:1445: in connect_to_master self.connect_to_master() locust/runners.py:1445: in connect_to_master self.connect_to_master() locust/runners.py:1445: in connect_to_master self.connect_to_master() locust/runners.py:1445: in connect_to_master self.connect_to_master() locust/runners.py:1445: in connect_to_master self.connect_to_master() locust/runners.py:1445: in connect_to_master self.connect_to_master() locust/runners.py:1445: in connect_to_master self.connect_to_master() locust/runners.py:1445: in connect_to_master self.connect_to_master() locust/runners.py:1445: in connect_to_master self.connect_to_master() locust/runners.py:1445: in connect_to_master self.connect_to_master() locust/runners.py:1445: in connect_to_master self.connect_to_master() locust/runners.py:1445: in connect_to_master self.connect_to_master() locust/runners.py:1445: in connect_to_master self.connect_to_master() locust/runners.py:1445: in connect_to_master self.connect_to_master() locust/runners.py:1445: in connect_to_master self.connect_to_master() _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = def connect_to_master(self): self.retry += 1 self.client.send(Message("client_ready", __version__, self.client_id)) try: success = self.connection_event.wait(timeout=CONNECT_TIMEOUT) except KeyboardInterrupt: # dont complain about getting CTRL-C sys.exit(1) if not success: if self.retry < 3: logger.debug( f"Failed to connect to master {self.master_host}:{self.master_port}, retry {self.retry}/{CONNECT_RETRY_COUNT}." ) else: logger.warning( f"Failed to connect to master {self.master_host}:{self.master_port}, retry {self.retry}/{CONNECT_RETRY_COUNT}." ) if self.retry > CONNECT_RETRY_COUNT: > raise ConnectionError() E ConnectionError locust/runners.py:1444: ConnectionError ------------------------------ Captured log call ------------------------------- ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (i-capture-the-hostname_b3adb018c0054cb7befc4dee7ac7ecd5). That's not going to work. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (i-capture-the-hostname_b3adb018c0054cb7befc4dee7ac7ecd5). That's not going to work. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (i-capture-the-hostname_b3adb018c0054cb7befc4dee7ac7ecd5). That's not going to work. WARNING locust.runners:runners.py:1440 Failed to connect to master 127.0.0.1:5558, retry 3/60. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (i-capture-the-hostname_b3adb018c0054cb7befc4dee7ac7ecd5). That's not going to work. WARNING locust.runners:runners.py:1440 Failed to connect to master 127.0.0.1:5558, retry 4/60. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (i-capture-the-hostname_b3adb018c0054cb7befc4dee7ac7ecd5). That's not going to work. WARNING locust.runners:runners.py:1440 Failed to connect to master 127.0.0.1:5558, retry 5/60. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (i-capture-the-hostname_b3adb018c0054cb7befc4dee7ac7ecd5). That's not going to work. WARNING locust.runners:runners.py:1440 Failed to connect to master 127.0.0.1:5558, retry 6/60. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (i-capture-the-hostname_b3adb018c0054cb7befc4dee7ac7ecd5). That's not going to work. WARNING locust.runners:runners.py:1440 Failed to connect to master 127.0.0.1:5558, retry 7/60. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (i-capture-the-hostname_b3adb018c0054cb7befc4dee7ac7ecd5). That's not going to work. WARNING locust.runners:runners.py:1440 Failed to connect to master 127.0.0.1:5558, retry 8/60. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (i-capture-the-hostname_b3adb018c0054cb7befc4dee7ac7ecd5). That's not going to work. WARNING locust.runners:runners.py:1440 Failed to connect to master 127.0.0.1:5558, retry 9/60. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (i-capture-the-hostname_b3adb018c0054cb7befc4dee7ac7ecd5). That's not going to work. WARNING locust.runners:runners.py:1440 Failed to connect to master 127.0.0.1:5558, retry 10/60. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (i-capture-the-hostname_b3adb018c0054cb7befc4dee7ac7ecd5). That's not going to work. WARNING locust.runners:runners.py:1440 Failed to connect to master 127.0.0.1:5558, retry 11/60. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (i-capture-the-hostname_b3adb018c0054cb7befc4dee7ac7ecd5). That's not going to work. WARNING locust.runners:runners.py:1440 Failed to connect to master 127.0.0.1:5558, retry 12/60. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (i-capture-the-hostname_b3adb018c0054cb7befc4dee7ac7ecd5). That's not going to work. WARNING locust.runners:runners.py:1440 Failed to connect to master 127.0.0.1:5558, retry 13/60. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (i-capture-the-hostname_b3adb018c0054cb7befc4dee7ac7ecd5). That's not going to work. WARNING locust.runners:runners.py:1440 Failed to connect to master 127.0.0.1:5558, retry 14/60. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (i-capture-the-hostname_b3adb018c0054cb7befc4dee7ac7ecd5). That's not going to work. WARNING locust.runners:runners.py:1440 Failed to connect to master 127.0.0.1:5558, retry 15/60. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (i-capture-the-hostname_b3adb018c0054cb7befc4dee7ac7ecd5). That's not going to work. WARNING locust.runners:runners.py:1440 Failed to connect to master 127.0.0.1:5558, retry 16/60. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (i-capture-the-hostname_b3adb018c0054cb7befc4dee7ac7ecd5). That's not going to work. WARNING locust.runners:runners.py:1440 Failed to connect to master 127.0.0.1:5558, retry 17/60. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (i-capture-the-hostname_b3adb018c0054cb7befc4dee7ac7ecd5). That's not going to work. WARNING locust.runners:runners.py:1440 Failed to connect to master 127.0.0.1:5558, retry 18/60. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (i-capture-the-hostname_b3adb018c0054cb7befc4dee7ac7ecd5). That's not going to work. WARNING locust.runners:runners.py:1440 Failed to connect to master 127.0.0.1:5558, retry 19/60. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (i-capture-the-hostname_b3adb018c0054cb7befc4dee7ac7ecd5). That's not going to work. WARNING locust.runners:runners.py:1440 Failed to connect to master 127.0.0.1:5558, retry 20/60. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (i-capture-the-hostname_b3adb018c0054cb7befc4dee7ac7ecd5). That's not going to work. WARNING locust.runners:runners.py:1440 Failed to connect to master 127.0.0.1:5558, retry 21/60. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (i-capture-the-hostname_b3adb018c0054cb7befc4dee7ac7ecd5). That's not going to work. WARNING locust.runners:runners.py:1440 Failed to connect to master 127.0.0.1:5558, retry 22/60. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (i-capture-the-hostname_b3adb018c0054cb7befc4dee7ac7ecd5). That's not going to work. WARNING locust.runners:runners.py:1440 Failed to connect to master 127.0.0.1:5558, retry 23/60. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (i-capture-the-hostname_b3adb018c0054cb7befc4dee7ac7ecd5). That's not going to work. WARNING locust.runners:runners.py:1440 Failed to connect to master 127.0.0.1:5558, retry 24/60. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (i-capture-the-hostname_b3adb018c0054cb7befc4dee7ac7ecd5). That's not going to work. WARNING locust.runners:runners.py:1440 Failed to connect to master 127.0.0.1:5558, retry 25/60. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (i-capture-the-hostname_b3adb018c0054cb7befc4dee7ac7ecd5). That's not going to work. WARNING locust.runners:runners.py:1440 Failed to connect to master 127.0.0.1:5558, retry 26/60. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (i-capture-the-hostname_b3adb018c0054cb7befc4dee7ac7ecd5). That's not going to work. WARNING locust.runners:runners.py:1440 Failed to connect to master 127.0.0.1:5558, retry 27/60. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (i-capture-the-hostname_b3adb018c0054cb7befc4dee7ac7ecd5). That's not going to work. WARNING locust.runners:runners.py:1440 Failed to connect to master 127.0.0.1:5558, retry 28/60. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (i-capture-the-hostname_b3adb018c0054cb7befc4dee7ac7ecd5). That's not going to work. WARNING locust.runners:runners.py:1440 Failed to connect to master 127.0.0.1:5558, retry 29/60. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (i-capture-the-hostname_b3adb018c0054cb7befc4dee7ac7ecd5). That's not going to work. WARNING locust.runners:runners.py:1440 Failed to connect to master 127.0.0.1:5558, retry 30/60. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (i-capture-the-hostname_b3adb018c0054cb7befc4dee7ac7ecd5). That's not going to work. WARNING locust.runners:runners.py:1440 Failed to connect to master 127.0.0.1:5558, retry 31/60. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (i-capture-the-hostname_b3adb018c0054cb7befc4dee7ac7ecd5). That's not going to work. WARNING locust.runners:runners.py:1440 Failed to connect to master 127.0.0.1:5558, retry 32/60. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (i-capture-the-hostname_b3adb018c0054cb7befc4dee7ac7ecd5). That's not going to work. WARNING locust.runners:runners.py:1440 Failed to connect to master 127.0.0.1:5558, retry 33/60. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (i-capture-the-hostname_b3adb018c0054cb7befc4dee7ac7ecd5). That's not going to work. WARNING locust.runners:runners.py:1440 Failed to connect to master 127.0.0.1:5558, retry 34/60. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (i-capture-the-hostname_b3adb018c0054cb7befc4dee7ac7ecd5). That's not going to work. WARNING locust.runners:runners.py:1440 Failed to connect to master 127.0.0.1:5558, retry 35/60. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (i-capture-the-hostname_b3adb018c0054cb7befc4dee7ac7ecd5). That's not going to work. WARNING locust.runners:runners.py:1440 Failed to connect to master 127.0.0.1:5558, retry 36/60. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (i-capture-the-hostname_b3adb018c0054cb7befc4dee7ac7ecd5). That's not going to work. WARNING locust.runners:runners.py:1440 Failed to connect to master 127.0.0.1:5558, retry 37/60. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (i-capture-the-hostname_b3adb018c0054cb7befc4dee7ac7ecd5). That's not going to work. WARNING locust.runners:runners.py:1440 Failed to connect to master 127.0.0.1:5558, retry 38/60. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (i-capture-the-hostname_b3adb018c0054cb7befc4dee7ac7ecd5). That's not going to work. WARNING locust.runners:runners.py:1440 Failed to connect to master 127.0.0.1:5558, retry 39/60. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (i-capture-the-hostname_b3adb018c0054cb7befc4dee7ac7ecd5). That's not going to work. WARNING locust.runners:runners.py:1440 Failed to connect to master 127.0.0.1:5558, retry 40/60. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (i-capture-the-hostname_b3adb018c0054cb7befc4dee7ac7ecd5). That's not going to work. WARNING locust.runners:runners.py:1440 Failed to connect to master 127.0.0.1:5558, retry 41/60. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (i-capture-the-hostname_b3adb018c0054cb7befc4dee7ac7ecd5). That's not going to work. WARNING locust.runners:runners.py:1440 Failed to connect to master 127.0.0.1:5558, retry 42/60. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (i-capture-the-hostname_b3adb018c0054cb7befc4dee7ac7ecd5). That's not going to work. WARNING locust.runners:runners.py:1440 Failed to connect to master 127.0.0.1:5558, retry 43/60. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (i-capture-the-hostname_b3adb018c0054cb7befc4dee7ac7ecd5). That's not going to work. WARNING locust.runners:runners.py:1440 Failed to connect to master 127.0.0.1:5558, retry 44/60. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (i-capture-the-hostname_b3adb018c0054cb7befc4dee7ac7ecd5). That's not going to work. WARNING locust.runners:runners.py:1440 Failed to connect to master 127.0.0.1:5558, retry 45/60. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (i-capture-the-hostname_b3adb018c0054cb7befc4dee7ac7ecd5). That's not going to work. WARNING locust.runners:runners.py:1440 Failed to connect to master 127.0.0.1:5558, retry 46/60. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (i-capture-the-hostname_b3adb018c0054cb7befc4dee7ac7ecd5). That's not going to work. WARNING locust.runners:runners.py:1440 Failed to connect to master 127.0.0.1:5558, retry 47/60. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (i-capture-the-hostname_b3adb018c0054cb7befc4dee7ac7ecd5). That's not going to work. WARNING locust.runners:runners.py:1440 Failed to connect to master 127.0.0.1:5558, retry 48/60. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (i-capture-the-hostname_b3adb018c0054cb7befc4dee7ac7ecd5). That's not going to work. WARNING locust.runners:runners.py:1440 Failed to connect to master 127.0.0.1:5558, retry 49/60. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (i-capture-the-hostname_b3adb018c0054cb7befc4dee7ac7ecd5). That's not going to work. WARNING locust.runners:runners.py:1440 Failed to connect to master 127.0.0.1:5558, retry 50/60. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (i-capture-the-hostname_b3adb018c0054cb7befc4dee7ac7ecd5). That's not going to work. WARNING locust.runners:runners.py:1440 Failed to connect to master 127.0.0.1:5558, retry 51/60. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (i-capture-the-hostname_b3adb018c0054cb7befc4dee7ac7ecd5). That's not going to work. WARNING locust.runners:runners.py:1440 Failed to connect to master 127.0.0.1:5558, retry 52/60. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (i-capture-the-hostname_b3adb018c0054cb7befc4dee7ac7ecd5). That's not going to work. WARNING locust.runners:runners.py:1440 Failed to connect to master 127.0.0.1:5558, retry 53/60. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (i-capture-the-hostname_b3adb018c0054cb7befc4dee7ac7ecd5). That's not going to work. WARNING locust.runners:runners.py:1440 Failed to connect to master 127.0.0.1:5558, retry 54/60. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (i-capture-the-hostname_b3adb018c0054cb7befc4dee7ac7ecd5). That's not going to work. WARNING locust.runners:runners.py:1440 Failed to connect to master 127.0.0.1:5558, retry 55/60. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (i-capture-the-hostname_b3adb018c0054cb7befc4dee7ac7ecd5). That's not going to work. WARNING locust.runners:runners.py:1440 Failed to connect to master 127.0.0.1:5558, retry 56/60. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (i-capture-the-hostname_b3adb018c0054cb7befc4dee7ac7ecd5). That's not going to work. WARNING locust.runners:runners.py:1440 Failed to connect to master 127.0.0.1:5558, retry 57/60. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (i-capture-the-hostname_b3adb018c0054cb7befc4dee7ac7ecd5). That's not going to work. WARNING locust.runners:runners.py:1440 Failed to connect to master 127.0.0.1:5558, retry 58/60. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (i-capture-the-hostname_b3adb018c0054cb7befc4dee7ac7ecd5). That's not going to work. WARNING locust.runners:runners.py:1440 Failed to connect to master 127.0.0.1:5558, retry 59/60. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (i-capture-the-hostname_b3adb018c0054cb7befc4dee7ac7ecd5). That's not going to work. WARNING locust.runners:runners.py:1440 Failed to connect to master 127.0.0.1:5558, retry 60/60. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (i-capture-the-hostname_b3adb018c0054cb7befc4dee7ac7ecd5). That's not going to work. WARNING locust.runners:runners.py:1440 Failed to connect to master 127.0.0.1:5558, retry 61/60. ______________ TestCsvStats.test_user_count_in_csv_history_stats _______________ self = @mock.patch("locust.stats.CSV_STATS_INTERVAL_SEC", new=_TEST_CSV_STATS_INTERVAL_SEC) def test_user_count_in_csv_history_stats(self): start_time = int(time.time()) class TestUser(User): wait_time = constant(10) @task def t(self): self.environment.runner.stats.log_request("GET", "/", 10, 10) environment = Environment(user_classes=[TestUser]) stats_writer = StatsCSVFileWriter(environment, PERCENTILES_TO_REPORT, self.STATS_BASE_NAME, full_history=True) runner = environment.create_local_runner() # spawn a user every _TEST_CSV_STATS_INTERVAL_SEC second user_count = 15 spawn_rate = 5 assert 1 / 5 == _TEST_CSV_STATS_INTERVAL_SEC runner_greenlet = gevent.spawn(runner.start, user_count, spawn_rate) gevent.sleep(0.1) greenlet = gevent.spawn(stats_writer) gevent.sleep(user_count / spawn_rate) gevent.kill(greenlet) stats_writer.close_files() runner.stop() gevent.kill(runner_greenlet) with open(self.STATS_HISTORY_FILENAME) as f: reader = csv.DictReader(f) rows = [r for r in reader] > self.assertEqual(2 * user_count, len(rows)) E AssertionError: 30 != 28 locust/test/test_stats.py:545: AssertionError ----------------------------- Captured stderr call ----------------------------- Traceback (most recent call last): File "src/gevent/greenlet.py", line 908, in gevent._gevent_cgreenlet.Greenlet.run File "/build/reproducible-path/locust-2.24.0/locust/stats.py", line 1090, in __call__ self.stats_writer() File "/build/reproducible-path/locust-2.24.0/locust/stats.py", line 1112, in stats_writer self.requests_csv_filehandle.seek(requests_csv_data_start) ValueError: I/O operation on closed file. 2024-05-09T12:03:43Z failed with ValueError ------------------------------ Captured log call ------------------------------- INFO locust.runners:runners.py:499 Ramping to 15 users at a rate of 5.00 per second INFO locust.runners:runners.py:537 All users spawned: {"TestUser": 15} (15 total users) ____________________ TestWaitTime.test_constant_throughput _____________________ self = def test_constant_throughput(self): class MyUser(User): wait_time = constant_throughput(10) class TS(TaskSet): pass ts = TS(MyUser(self.environment)) ts2 = TS(MyUser(self.environment)) previous_time = time.perf_counter() for i in range(7): ts.wait() since_last_run = time.perf_counter() - previous_time > self.assertLess(abs(0.1 - since_last_run), 0.02) E AssertionError: 0.023899360994982993 not less than 0.02 locust/test/test_wait_time.py:75: AssertionError ------------------------------ Captured log call ------------------------------- WARNING root:runners.py:305 CPU usage above 90%! This may constrain your throughput and may even give inconsistent response time measurements! See https://docs.locust.io/en/stable/running-distributed.html for how to distribute the load over multiple CPU cores or machines WARNING root:runners.py:305 CPU usage above 90%! This may constrain your throughput and may even give inconsistent response time measurements! See https://docs.locust.io/en/stable/running-distributed.html for how to distribute the load over multiple CPU cores or machines WARNING root:runners.py:305 CPU usage above 90%! This may constrain your throughput and may even give inconsistent response time measurements! See https://docs.locust.io/en/stable/running-distributed.html for how to distribute the load over multiple CPU cores or machines WARNING root:runners.py:305 CPU usage above 90%! This may constrain your throughput and may even give inconsistent response time measurements! See https://docs.locust.io/en/stable/running-distributed.html for how to distribute the load over multiple CPU cores or machines WARNING root:runners.py:305 CPU usage above 90%! This may constrain your throughput and may even give inconsistent response time measurements! See https://docs.locust.io/en/stable/running-distributed.html for how to distribute the load over multiple CPU cores or machines WARNING root:runners.py:305 CPU usage above 90%! This may constrain your throughput and may even give inconsistent response time measurements! See https://docs.locust.io/en/stable/running-distributed.html for how to distribute the load over multiple CPU cores or machines WARNING root:runners.py:305 CPU usage above 90%! This may constrain your throughput and may even give inconsistent response time measurements! See https://docs.locust.io/en/stable/running-distributed.html for how to distribute the load over multiple CPU cores or machines WARNING root:runners.py:305 CPU usage above 90%! This may constrain your throughput and may even give inconsistent response time measurements! See https://docs.locust.io/en/stable/running-distributed.html for how to distribute the load over multiple CPU cores or machines WARNING root:runners.py:305 CPU usage above 90%! This may constrain your throughput and may even give inconsistent response time measurements! See https://docs.locust.io/en/stable/running-distributed.html for how to distribute the load over multiple CPU cores or machines WARNING root:runners.py:305 CPU usage above 90%! This may constrain your throughput and may even give inconsistent response time measurements! See https://docs.locust.io/en/stable/running-distributed.html for how to distribute the load over multiple CPU cores or machines WARNING root:runners.py:305 CPU usage above 90%! This may constrain your throughput and may even give inconsistent response time measurements! See https://docs.locust.io/en/stable/running-distributed.html for how to distribute the load over multiple CPU cores or machines WARNING root:runners.py:305 CPU usage above 90%! This may constrain your throughput and may even give inconsistent response time measurements! See https://docs.locust.io/en/stable/running-distributed.html for how to distribute the load over multiple CPU cores or machines WARNING root:runners.py:305 CPU usage above 90%! This may constrain your throughput and may even give inconsistent response time measurements! See https://docs.locust.io/en/stable/running-distributed.html for how to distribute the load over multiple CPU cores or machines WARNING root:runners.py:305 CPU usage above 90%! This may constrain your throughput and may even give inconsistent response time measurements! See https://docs.locust.io/en/stable/running-distributed.html for how to distribute the load over multiple CPU cores or machines WARNING root:runners.py:305 CPU usage above 90%! This may constrain your throughput and may even give inconsistent response time measurements! See https://docs.locust.io/en/stable/running-distributed.html for how to distribute the load over multiple CPU cores or machines WARNING root:runners.py:305 CPU usage above 90%! This may constrain your throughput and may even give inconsistent response time measurements! See https://docs.locust.io/en/stable/running-distributed.html for how to distribute the load over multiple CPU cores or machines WARNING root:runners.py:305 CPU usage above 90%! This may constrain your throughput and may even give inconsistent response time measurements! See https://docs.locust.io/en/stable/running-distributed.html for how to distribute the load over multiple CPU cores or machines _____________________ TestWaitTime.test_default_wait_time ______________________ self = def test_default_wait_time(self): class MyUser(User): pass # default is wait_time = constant(0) class TaskSet1(TaskSet): pass self.assertEqual(0, MyUser(self.environment).wait_time()) self.assertEqual(0, TaskSet1(MyUser(self.environment)).wait_time()) taskset = TaskSet1(MyUser(self.environment)) start_time = time.perf_counter() taskset.wait() > self.assertLess(time.perf_counter() - start_time, 0.002) E AssertionError: 0.0033665779992588796 not less than 0.002 locust/test/test_wait_time.py:58: AssertionError ------------------------------ Captured log call ------------------------------- WARNING root:runners.py:305 CPU usage above 90%! This may constrain your throughput and may even give inconsistent response time measurements! See https://docs.locust.io/en/stable/running-distributed.html for how to distribute the load over multiple CPU cores or machines WARNING root:runners.py:305 CPU usage above 90%! This may constrain your throughput and may even give inconsistent response time measurements! See https://docs.locust.io/en/stable/running-distributed.html for how to distribute the load over multiple CPU cores or machines WARNING root:runners.py:305 CPU usage above 90%! This may constrain your throughput and may even give inconsistent response time measurements! See https://docs.locust.io/en/stable/running-distributed.html for how to distribute the load over multiple CPU cores or machines WARNING root:runners.py:305 CPU usage above 90%! This may constrain your throughput and may even give inconsistent response time measurements! See https://docs.locust.io/en/stable/running-distributed.html for how to distribute the load over multiple CPU cores or machines WARNING root:runners.py:305 CPU usage above 90%! This may constrain your throughput and may even give inconsistent response time measurements! See https://docs.locust.io/en/stable/running-distributed.html for how to distribute the load over multiple CPU cores or machines WARNING root:runners.py:305 CPU usage above 90%! This may constrain your throughput and may even give inconsistent response time measurements! See https://docs.locust.io/en/stable/running-distributed.html for how to distribute the load over multiple CPU cores or machines WARNING root:runners.py:305 CPU usage above 90%! This may constrain your throughput and may even give inconsistent response time measurements! See https://docs.locust.io/en/stable/running-distributed.html for how to distribute the load over multiple CPU cores or machines WARNING root:runners.py:305 CPU usage above 90%! This may constrain your throughput and may even give inconsistent response time measurements! See https://docs.locust.io/en/stable/running-distributed.html for how to distribute the load over multiple CPU cores or machines WARNING root:runners.py:305 CPU usage above 90%! This may constrain your throughput and may even give inconsistent response time measurements! See https://docs.locust.io/en/stable/running-distributed.html for how to distribute the load over multiple CPU cores or machines WARNING root:runners.py:305 CPU usage above 90%! This may constrain your throughput and may even give inconsistent response time measurements! See https://docs.locust.io/en/stable/running-distributed.html for how to distribute the load over multiple CPU cores or machines WARNING root:runners.py:305 CPU usage above 90%! This may constrain your throughput and may even give inconsistent response time measurements! See https://docs.locust.io/en/stable/running-distributed.html for how to distribute the load over multiple CPU cores or machines WARNING root:runners.py:305 CPU usage above 90%! This may constrain your throughput and may even give inconsistent response time measurements! See https://docs.locust.io/en/stable/running-distributed.html for how to distribute the load over multiple CPU cores or machines WARNING root:runners.py:305 CPU usage above 90%! This may constrain your throughput and may even give inconsistent response time measurements! See https://docs.locust.io/en/stable/running-distributed.html for how to distribute the load over multiple CPU cores or machines WARNING root:runners.py:305 CPU usage above 90%! This may constrain your throughput and may even give inconsistent response time measurements! See https://docs.locust.io/en/stable/running-distributed.html for how to distribute the load over multiple CPU cores or machines WARNING root:runners.py:305 CPU usage above 90%! This may constrain your throughput and may even give inconsistent response time measurements! See https://docs.locust.io/en/stable/running-distributed.html for how to distribute the load over multiple CPU cores or machines WARNING root:runners.py:305 CPU usage above 90%! This may constrain your throughput and may even give inconsistent response time measurements! See https://docs.locust.io/en/stable/running-distributed.html for how to distribute the load over multiple CPU cores or machines WARNING root:runners.py:305 CPU usage above 90%! This may constrain your throughput and may even give inconsistent response time measurements! See https://docs.locust.io/en/stable/running-distributed.html for how to distribute the load over multiple CPU cores or machines WARNING root:runners.py:305 CPU usage above 90%! This may constrain your throughput and may even give inconsistent response time measurements! See https://docs.locust.io/en/stable/running-distributed.html for how to distribute the load over multiple CPU cores or machines WARNING root:runners.py:305 CPU usage above 90%! This may constrain your throughput and may even give inconsistent response time measurements! See https://docs.locust.io/en/stable/running-distributed.html for how to distribute the load over multiple CPU cores or machines WARNING root:runners.py:305 CPU usage above 90%! This may constrain your throughput and may even give inconsistent response time measurements! See https://docs.locust.io/en/stable/running-distributed.html for how to distribute the load over multiple CPU cores or machines WARNING root:runners.py:305 CPU usage above 90%! This may constrain your throughput and may even give inconsistent response time measurements! See https://docs.locust.io/en/stable/running-distributed.html for how to distribute the load over multiple CPU cores or machines WARNING root:runners.py:305 CPU usage above 90%! This may constrain your throughput and may even give inconsistent response time measurements! See https://docs.locust.io/en/stable/running-distributed.html for how to distribute the load over multiple CPU cores or machines WARNING root:runners.py:305 CPU usage above 90%! This may constrain your throughput and may even give inconsistent response time measurements! See https://docs.locust.io/en/stable/running-distributed.html for how to distribute the load over multiple CPU cores or machines WARNING root:runners.py:305 CPU usage above 90%! This may constrain your throughput and may even give inconsistent response time measurements! See https://docs.locust.io/en/stable/running-distributed.html for how to distribute the load over multiple CPU cores or machines =============================== warnings summary =============================== locust/test/test_fasthttp.py::TestFastHttpSsl::test_ssl_request_insecure locust/test/test_web.py::TestWebUIWithTLS::test_index_with_https /usr/lib/python3/dist-packages/gevent/ssl.py:237: DeprecationWarning: ssl.PROTOCOL_TLS is deprecated self._context = SSLContext(ssl_version) locust/test/test_log.py: 4 warnings locust/test/test_main.py: 38 warnings /usr/lib/python3/dist-packages/gevent/os.py:426: DeprecationWarning: This process (pid=259829) is multi-threaded, use of fork() may lead to deadlocks in the child. pid = fork() locust/test/test_web.py::TestWebUI::test_html_stats_report locust/test/test_web.py::TestWebUI::test_report_download locust/test/test_web.py::TestWebUI::test_report_exceptions locust/test/test_web.py::TestWebUI::test_report_host locust/test/test_web.py::TestWebUI::test_report_host2 locust/test/test_web.py::TestWebUI::test_report_page locust/test/test_web.py::TestWebUI::test_report_page_empty_stats locust/test/test_web.py::TestModernWebUI::test_html_stats_report /build/reproducible-path/locust-2.24.0/locust/html.py:42: DeprecationWarning: datetime.datetime.utcfromtimestamp() is deprecated and scheduled for removal in a future version. Use timezone-aware objects to represent datetimes in UTC: datetime.datetime.fromtimestamp(timestamp, datetime.UTC). start_time = datetime.datetime.utcfromtimestamp(start_ts).strftime("%Y-%m-%d %H:%M:%S") locust/test/test_web.py::TestWebUI::test_report_download locust/test/test_web.py::TestWebUI::test_report_exceptions locust/test/test_web.py::TestWebUI::test_report_host locust/test/test_web.py::TestWebUI::test_report_host2 locust/test/test_web.py::TestWebUI::test_report_page /build/reproducible-path/locust-2.24.0/locust/html.py:46: DeprecationWarning: datetime.datetime.utcfromtimestamp() is deprecated and scheduled for removal in a future version. Use timezone-aware objects to represent datetimes in UTC: datetime.datetime.fromtimestamp(timestamp, datetime.UTC). end_time = datetime.datetime.utcfromtimestamp(end_ts).strftime("%Y-%m-%d %H:%M:%S") -- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html =========================== short test summary info ============================ FAILED locust/test/test_http.py::TestHttpSession::test_event_measure - Assert... FAILED locust/test/test_load_locustfile.py::TestLoadLocustfile::test_locustfile_from_url FAILED locust/test/test_log.py::TestLoggingOptions::test_log_to_file - OSErro... FAILED locust/test/test_log.py::TestLoggingOptions::test_logging_output - OSE... FAILED locust/test/test_log.py::TestLoggingOptions::test_skip_logging - OSErr... FAILED locust/test/test_log.py::TestLoggingOptions::test_user_broken_on_start FAILED locust/test/test_main.py::StandaloneIntegrationTests::test_autostart_multiple_locustfiles_with_shape FAILED locust/test/test_main.py::StandaloneIntegrationTests::test_autostart_w_load_shape FAILED locust/test/test_main.py::StandaloneIntegrationTests::test_autostart_w_run_time FAILED locust/test/test_main.py::StandaloneIntegrationTests::test_autostart_wo_run_time FAILED locust/test/test_main.py::StandaloneIntegrationTests::test_command_line_user_selection FAILED locust/test/test_main.py::StandaloneIntegrationTests::test_custom_arguments FAILED locust/test/test_main.py::StandaloneIntegrationTests::test_custom_arguments_in_file FAILED locust/test/test_main.py::StandaloneIntegrationTests::test_custom_exit_code FAILED locust/test/test_main.py::StandaloneIntegrationTests::test_default_headless_spawn_options FAILED locust/test/test_main.py::StandaloneIntegrationTests::test_default_headless_spawn_options_with_shape FAILED locust/test/test_main.py::StandaloneIntegrationTests::test_error_when_duplicate_shape_class_names FAILED locust/test/test_main.py::StandaloneIntegrationTests::test_error_when_duplicate_userclass_names FAILED locust/test/test_main.py::StandaloneIntegrationTests::test_error_when_locustfiles_directory_is_empty FAILED locust/test/test_main.py::StandaloneIntegrationTests::test_error_when_no_tasks_match_tags FAILED locust/test/test_main.py::StandaloneIntegrationTests::test_error_when_providing_both_run_time_and_a_shape_class FAILED locust/test/test_main.py::StandaloneIntegrationTests::test_graceful_exit_when_keyboard_interrupt FAILED locust/test/test_main.py::StandaloneIntegrationTests::test_headless_spawn_options_wo_run_time FAILED locust/test/test_main.py::StandaloneIntegrationTests::test_help_arg - ... FAILED locust/test/test_main.py::StandaloneIntegrationTests::test_html_report_option FAILED locust/test/test_main.py::StandaloneIntegrationTests::test_input - Ass... FAILED locust/test/test_main.py::StandaloneIntegrationTests::test_invalid_percentile_parameter FAILED locust/test/test_main.py::StandaloneIntegrationTests::test_invalid_stop_timeout_string FAILED locust/test/test_main.py::StandaloneIntegrationTests::test_no_error_when_same_userclass_in_two_files FAILED locust/test/test_main.py::StandaloneIntegrationTests::test_percentile_parameter FAILED locust/test/test_main.py::StandaloneIntegrationTests::test_percentiles_to_statistics FAILED locust/test/test_main.py::StandaloneIntegrationTests::test_run_autostart_with_multiple_locustfiles FAILED locust/test/test_main.py::StandaloneIntegrationTests::test_run_headless_with_multiple_locustfiles FAILED locust/test/test_main.py::StandaloneIntegrationTests::test_run_headless_with_multiple_locustfiles_with_shape FAILED locust/test/test_main.py::StandaloneIntegrationTests::test_run_with_userclass_picker FAILED locust/test/test_main.py::StandaloneIntegrationTests::test_shape_class_log_disabled_parameters FAILED locust/test/test_main.py::StandaloneIntegrationTests::test_shape_class_with_use_common_options FAILED locust/test/test_main.py::StandaloneIntegrationTests::test_spawing_with_fixed_multiple_locustfiles FAILED locust/test/test_main.py::StandaloneIntegrationTests::test_spawning_with_fixed FAILED locust/test/test_main.py::StandaloneIntegrationTests::test_web_options FAILED locust/test/test_main.py::StandaloneIntegrationTests::test_webserver FAILED locust/test/test_main.py::StandaloneIntegrationTests::test_webserver_multiple_locustfiles FAILED locust/test/test_main.py::StandaloneIntegrationTests::test_webserver_multiple_locustfiles_in_directory FAILED locust/test/test_main.py::StandaloneIntegrationTests::test_webserver_multiple_locustfiles_with_shape FAILED locust/test/test_main.py::DistributedIntegrationTests::test_distributed FAILED locust/test/test_main.py::DistributedIntegrationTests::test_distributed_events FAILED locust/test/test_main.py::DistributedIntegrationTests::test_distributed_report_timeout_expired FAILED locust/test/test_main.py::DistributedIntegrationTests::test_distributed_tags FAILED locust/test/test_main.py::DistributedIntegrationTests::test_distributed_with_locustfile_distribution_not_plain_filename FAILED locust/test/test_main.py::DistributedIntegrationTests::test_expect_workers FAILED locust/test/test_main.py::DistributedIntegrationTests::test_json_schema FAILED locust/test/test_main.py::DistributedIntegrationTests::test_locustfile_distribution FAILED locust/test/test_main.py::DistributedIntegrationTests::test_locustfile_distribution_with_workers_started_first FAILED locust/test/test_main.py::DistributedIntegrationTests::test_processes FAILED locust/test/test_main.py::DistributedIntegrationTests::test_processes_autodetect FAILED locust/test/test_main.py::DistributedIntegrationTests::test_processes_ctrl_c FAILED locust/test/test_main.py::DistributedIntegrationTests::test_processes_error_doesnt_blow_up_completely FAILED locust/test/test_main.py::DistributedIntegrationTests::test_processes_separate_worker FAILED locust/test/test_main.py::DistributedIntegrationTests::test_processes_workers_quit_unexpected FAILED locust/test/test_main.py::DistributedIntegrationTests::test_worker_indexes FAILED locust/test/test_main.py::DistributedIntegrationTests::test_workers_shut_down_if_master_is_gone FAILED locust/test/test_runners.py::TestLocustRunner::test_cpu_warning - Asse... FAILED locust/test/test_runners.py::TestLocustRunner::test_stop_users_with_spawn_rate FAILED locust/test/test_runners.py::TestMasterRunner::test_attributes_populated_when_calling_start FAILED locust/test/test_runners.py::TestMasterRunner::test_custom_shape_scale_down FAILED locust/test/test_runners.py::TestMasterRunner::test_custom_shape_scale_interval FAILED locust/test/test_runners.py::TestMasterRunner::test_custom_shape_scale_up FAILED locust/test/test_runners.py::TestMasterRunner::test_last_worker_missing_stops_test FAILED locust/test/test_runners.py::TestMasterRunner::test_last_worker_quitting_stops_test FAILED locust/test/test_runners.py::TestMasterRunner::test_master_discard_first_client_ready FAILED locust/test/test_runners.py::TestMasterRunner::test_master_marks_downed_workers_as_missing FAILED locust/test/test_runners.py::TestMasterRunner::test_master_reset_connection FAILED locust/test/test_runners.py::TestMasterRunner::test_rebalance_locust_users_on_worker_connect FAILED locust/test/test_runners.py::TestMasterRunner::test_reset_connection_after_RPCError FAILED locust/test/test_runners.py::TestMasterRunner::test_spawn_correct_worker_indexes FAILED locust/test/test_runners.py::TestMasterRunner::test_spawn_fewer_locusts_than_workers FAILED locust/test/test_runners.py::TestMasterRunner::test_spawn_uneven_locusts FAILED locust/test/test_runners.py::TestMasterRunner::test_start_event - Asse... FAILED locust/test/test_runners.py::TestMasterRunner::test_stop_event - Asser... FAILED locust/test/test_runners.py::TestMasterRunner::test_stop_event_quit - ... FAILED locust/test/test_runners.py::TestMasterRunner::test_unknown_host_sends_message_to_master FAILED locust/test/test_runners.py::TestMasterRunner::test_worker_connect - A... FAILED locust/test/test_runners.py::TestMasterRunner::test_worker_connect_with_special_versions FAILED locust/test/test_runners.py::TestMasterRunner::test_worker_missing_after_heartbeat_dead_interval FAILED locust/test/test_runners.py::TestMasterRunner::test_worker_sends_bad_message_to_master FAILED locust/test/test_runners.py::TestMasterRunner::test_worker_sends_unrecognized_message_to_master FAILED locust/test/test_runners.py::TestStopTimeout::test_kill_locusts_with_stop_timeout FAILED locust/test/test_runners.py::TestStopTimeout::test_stop_timeout - Asse... FAILED locust/test/test_runners.py::TestStopTimeout::test_stop_timeout_during_on_start FAILED locust/test/test_runners.py::TestStopTimeout::test_stop_timeout_exit_during_wait FAILED locust/test/test_runners.py::TestStopTimeout::test_stop_timeout_with_interrupt_no_reschedule FAILED locust/test/test_stats.py::TestCsvStats::test_stats_history - Connecti... FAILED locust/test/test_stats.py::TestCsvStats::test_user_count_in_csv_history_stats FAILED locust/test/test_wait_time.py::TestWaitTime::test_constant_throughput FAILED locust/test/test_wait_time.py::TestWaitTime::test_default_wait_time - ... = 95 failed, 453 passed, 1 skipped, 15 deselected, 57 warnings in 561.58s (0:09:21) = E: pybuild pybuild:389: test: plugin custom failed with: exit code=1: PYTHONPATH=/build/reproducible-path/locust-2.24.0/.pybuild/cpython3_3.12_locust/build python3.12 -m pytest -v --ignore=examples/test_data_management.py -k 'not TestMasterWorkerRunners' I: pybuild base:311: PYTHONPATH=/build/reproducible-path/locust-2.24.0/.pybuild/cpython3_3.11_locust/build python3.11 -m pytest -v --ignore=examples/test_data_management.py -k 'not TestMasterWorkerRunners' ============================= test session starts ============================== platform linux -- Python 3.11.9, pytest-7.4.4, pluggy-1.5.0 -- /usr/bin/python3.11 cachedir: .pytest_cache rootdir: /build/reproducible-path/locust-2.24.0 collecting ... collected 564 items / 15 deselected / 549 selected locust/test/test_debugging.py::TestDebugging::test_run_single_user_pass_host_to_user_classes PASSED [ 0%] locust/test/test_dispatch.py::TestRampUpUsersFromZero::test_ramp_up_users_to_3_workers_with_spawn_rate_of_0_5 PASSED [ 0%] locust/test/test_dispatch.py::TestRampUpUsersFromZero::test_ramp_up_users_to_3_workers_with_spawn_rate_of_1 PASSED [ 0%] locust/test/test_dispatch.py::TestRampUpUsersFromZero::test_ramp_up_users_to_3_workers_with_spawn_rate_of_2 PASSED [ 0%] locust/test/test_dispatch.py::TestRampUpUsersFromZero::test_ramp_up_users_to_3_workers_with_spawn_rate_of_2_4 PASSED [ 0%] locust/test/test_dispatch.py::TestRampUpUsersFromZero::test_ramp_up_users_to_3_workers_with_spawn_rate_of_3 PASSED [ 1%] locust/test/test_dispatch.py::TestRampUpUsersFromZero::test_ramp_up_users_to_3_workers_with_spawn_rate_of_4 PASSED [ 1%] locust/test/test_dispatch.py::TestRampUpUsersFromZero::test_ramp_up_users_to_3_workers_with_spawn_rate_of_9 PASSED [ 1%] locust/test/test_dispatch.py::TestRampUpUsersFromZero::test_ramp_up_users_to_4_workers_with_spawn_rate_of_1 PASSED [ 1%] locust/test/test_dispatch.py::TestRampUpUsersFromZero::test_users_are_distributed_evenly_across_hosts PASSED [ 1%] locust/test/test_dispatch.py::TestWaitBetweenDispatch::test_wait_between_dispatch PASSED [ 2%] locust/test/test_dispatch.py::TestRampDownUsersToZero::test_ramp_down_users_to_3_workers_with_spawn_rate_of_0_5 PASSED [ 2%] locust/test/test_dispatch.py::TestRampDownUsersToZero::test_ramp_down_users_to_3_workers_with_spawn_rate_of_1 PASSED [ 2%] locust/test/test_dispatch.py::TestRampDownUsersToZero::test_ramp_down_users_to_3_workers_with_spawn_rate_of_2 PASSED [ 2%] locust/test/test_dispatch.py::TestRampDownUsersToZero::test_ramp_down_users_to_3_workers_with_spawn_rate_of_2_4 PASSED [ 2%] locust/test/test_dispatch.py::TestRampDownUsersToZero::test_ramp_down_users_to_3_workers_with_spawn_rate_of_3 PASSED [ 2%] locust/test/test_dispatch.py::TestRampDownUsersToZero::test_ramp_down_users_to_3_workers_with_spawn_rate_of_4 PASSED [ 3%] locust/test/test_dispatch.py::TestRampDownUsersToZero::test_ramp_down_users_to_3_workers_with_spawn_rate_of_9 PASSED [ 3%] locust/test/test_dispatch.py::TestRampDownUsersToZero::test_ramp_down_users_to_4_workers_with_spawn_rate_of_1 PASSED [ 3%] locust/test/test_dispatch.py::TestRampUpThenDownThenUp::test_ramp_up_then_down_then_up SKIPPED [ 3%] locust/test/test_dispatch.py::TestDispatchUsersToWorkersHavingTheSameUsersAsTheTarget::test_dispatch_users_to_3_workers PASSED [ 3%] locust/test/test_dispatch.py::TestDistributionIsRespectedDuringDispatch::test_dispatch_75_users_to_4_workers_with_spawn_rate_of_5 PASSED [ 4%] locust/test/test_dispatch.py::TestLargeScale::test_distribute_users PASSED [ 4%] locust/test/test_dispatch.py::TestLargeScale::test_ramp_down_from_100_000_to_0_users_with_50_user_classes_and_1000_workers_and_5000_spawn_rate PASSED [ 4%] locust/test/test_dispatch.py::TestLargeScale::test_ramp_up_from_0_to_100_000_users_with_50_user_classes_and_1000_workers_and_5000_spawn_rate PASSED [ 4%] locust/test/test_dispatch.py::TestSmallConsecutiveRamping::test_consecutive_ramp_up_and_ramp_down PASSED [ 4%] locust/test/test_dispatch.py::TestRampingMiscellaneous::test_spawn_rate_greater_than_target_user_count PASSED [ 4%] locust/test/test_dispatch.py::TestRemoveWorker::test_remove_last_worker PASSED [ 5%] locust/test/test_dispatch.py::TestRemoveWorker::test_remove_two_workers_between_two_ramp_ups PASSED [ 5%] locust/test/test_dispatch.py::TestRemoveWorker::test_remove_two_workers_during_ramp_down PASSED [ 5%] locust/test/test_dispatch.py::TestRemoveWorker::test_remove_two_workers_during_ramp_up PASSED [ 5%] locust/test/test_dispatch.py::TestRemoveWorker::test_remove_worker_between_two_ramp_ups PASSED [ 5%] locust/test/test_dispatch.py::TestRemoveWorker::test_remove_worker_during_ramp_down PASSED [ 6%] locust/test/test_dispatch.py::TestRemoveWorker::test_remove_worker_during_ramp_up PASSED [ 6%] locust/test/test_dispatch.py::TestRemoveWorker::test_remove_worker_during_ramp_up_with_fixed_user PASSED [ 6%] locust/test/test_dispatch.py::TestAddWorker::test_add_two_workers_between_two_ramp_ups PASSED [ 6%] locust/test/test_dispatch.py::TestAddWorker::test_add_two_workers_during_ramp_down PASSED [ 6%] locust/test/test_dispatch.py::TestAddWorker::test_add_two_workers_during_ramp_up PASSED [ 6%] locust/test/test_dispatch.py::TestAddWorker::test_add_worker_between_two_ramp_ups PASSED [ 7%] locust/test/test_dispatch.py::TestAddWorker::test_add_worker_during_ramp_down PASSED [ 7%] locust/test/test_dispatch.py::TestAddWorker::test_add_worker_during_ramp_up PASSED [ 7%] locust/test/test_dispatch.py::TestAddWorker::test_add_worker_during_ramp_up_with_fixed_user PASSED [ 7%] locust/test/test_dispatch.py::TestRampUpUsersFromZeroWithFixed::test_ramp_up_2_weigted_user_with_1_fixed_user PASSED [ 7%] locust/test/test_dispatch.py::TestRampUpUsersFromZeroWithFixed::test_ramp_up_only_fixed_users PASSED [ 8%] locust/test/test_dispatch.py::TestRampUpUsersFromZeroWithFixed::test_ramp_up_partially_ramp_down_and_rump_up_to_target PASSED [ 8%] locust/test/test_dispatch.py::TestRampUpUsersFromZeroWithFixed::test_ramp_up_ramp_down_and_ramp_up_again PASSED [ 8%] locust/test/test_dispatch.py::TestRampUpUsersFromZeroWithFixed::test_ramp_up_ramp_down_and_ramp_up_again_single_fixed_class PASSED [ 8%] locust/test/test_dispatch.py::TestRampUpUsersFromZeroWithFixed::test_ramp_up_various_count_weigted_and_fixed_users PASSED [ 8%] locust/test/test_dispatch.py::TestRampUpDifferentUsers::test_add_worker_during_ramp_up_custom_classes PASSED [ 8%] locust/test/test_dispatch.py::TestRampUpDifferentUsers::test_ramp_down_custom_user_classes_respect_weighting PASSED [ 9%] locust/test/test_dispatch.py::TestRampUpDifferentUsers::test_ramp_up_different_users_each_dispatch_multiple_worker PASSED [ 9%] locust/test/test_dispatch.py::TestRampUpDifferentUsers::test_ramp_up_different_users_for_each_dispatch PASSED [ 9%] locust/test/test_dispatch.py::TestRampUpDifferentUsers::test_ramp_up_first_half_user1_second_half_user2 PASSED [ 9%] locust/test/test_dispatch.py::TestRampUpDifferentUsers::test_ramp_up_first_one_user_then_all_classes PASSED [ 9%] locust/test/test_dispatch.py::TestRampUpDifferentUsers::test_ramp_up_one_user_class_multiple_worker PASSED [ 10%] locust/test/test_dispatch.py::TestRampUpDifferentUsers::test_ramp_up_only_one_kind_of_user PASSED [ 10%] locust/test/test_dispatch.py::TestRampUpDifferentUsers::test_remove_worker_during_ramp_up_custom_classes PASSED [ 10%] locust/test/test_env.py::TestEnvironment::test_all_user_classes_with_zero_weight_raises_exception PASSED [ 10%] locust/test/test_env.py::TestEnvironment::test_assign_equal_weights PASSED [ 10%] locust/test/test_env.py::TestEnvironment::test_dispatcher_class_attribute PASSED [ 10%] locust/test/test_env.py::TestEnvironment::test_shape_class_attribute PASSED [ 11%] locust/test/test_env.py::TestEnvironment::test_update_user_class PASSED [ 11%] locust/test/test_env.py::TestEnvironment::test_user_classes_count PASSED [ 11%] locust/test/test_env.py::TestEnvironment::test_user_classes_with_same_name_is_error PASSED [ 11%] locust/test/test_env.py::TestEnvironment::test_user_classes_with_zero_weight_are_removed PASSED [ 11%] locust/test/test_fasthttp.py::TestFastHttpSession::test_204 PASSED [ 12%] locust/test/test_fasthttp.py::TestFastHttpSession::test_404 PASSED [ 12%] locust/test/test_fasthttp.py::TestFastHttpSession::test_catch_response_default_fail PASSED [ 12%] locust/test/test_fasthttp.py::TestFastHttpSession::test_catch_response_default_success PASSED [ 12%] locust/test/test_fasthttp.py::TestFastHttpSession::test_catch_response_fail_successful_request PASSED [ 12%] locust/test/test_fasthttp.py::TestFastHttpSession::test_catch_response_multiple_failure_and_success PASSED [ 12%] locust/test/test_fasthttp.py::TestFastHttpSession::test_catch_response_pass_failed_request PASSED [ 13%] locust/test/test_fasthttp.py::TestFastHttpSession::test_catch_response_pass_failed_request_with_other_exception_within_block PASSED [ 13%] locust/test/test_fasthttp.py::TestFastHttpSession::test_connection_error PASSED [ 13%] locust/test/test_fasthttp.py::TestFastHttpSession::test_cookie PASSED [ 13%] locust/test/test_fasthttp.py::TestFastHttpSession::test_custom_ssl_context_fail_with_bad_context PASSED [ 13%] locust/test/test_fasthttp.py::TestFastHttpSession::test_custom_ssl_context_passed_correct_to_client_pool PASSED [ 14%] locust/test/test_fasthttp.py::TestFastHttpSession::test_delete PASSED [ 14%] locust/test/test_fasthttp.py::TestFastHttpSession::test_error_message_with_name_replacement PASSED [ 14%] locust/test/test_fasthttp.py::TestFastHttpSession::test_get PASSED [ 14%] locust/test/test_fasthttp.py::TestFastHttpSession::test_head PASSED [ 14%] locust/test/test_fasthttp.py::TestFastHttpSession::test_json_payload PASSED [ 14%] locust/test/test_fasthttp.py::TestFastHttpSession::test_options PASSED [ 15%] locust/test/test_fasthttp.py::TestFastHttpSession::test_patch PASSED [ 15%] locust/test/test_fasthttp.py::TestFastHttpSession::test_post_redirect PASSED [ 15%] locust/test/test_fasthttp.py::TestFastHttpSession::test_slow_redirect PASSED [ 15%] locust/test/test_fasthttp.py::TestFastHttpSession::test_streaming_response PASSED [ 15%] locust/test/test_fasthttp.py::TestRequestStatsWithWebserver::test_request_connection_error PASSED [ 16%] locust/test/test_fasthttp.py::TestRequestStatsWithWebserver::test_request_stats_content_length PASSED [ 16%] locust/test/test_fasthttp.py::TestRequestStatsWithWebserver::test_request_stats_named_endpoint PASSED [ 16%] locust/test/test_fasthttp.py::TestRequestStatsWithWebserver::test_request_stats_no_content_length PASSED [ 16%] locust/test/test_fasthttp.py::TestRequestStatsWithWebserver::test_request_stats_no_content_length_streaming PASSED [ 16%] locust/test/test_fasthttp.py::TestRequestStatsWithWebserver::test_request_stats_put PASSED [ 16%] locust/test/test_fasthttp.py::TestRequestStatsWithWebserver::test_request_stats_query_variables PASSED [ 17%] locust/test/test_fasthttp.py::TestFastHttpUserClass::test_allow_redirects_override PASSED [ 17%] locust/test/test_fasthttp.py::TestFastHttpUserClass::test_class_context PASSED [ 17%] locust/test/test_fasthttp.py::TestFastHttpUserClass::test_client_basic_auth PASSED [ 17%] locust/test/test_fasthttp.py::TestFastHttpUserClass::test_client_delete PASSED [ 17%] locust/test/test_fasthttp.py::TestFastHttpUserClass::test_client_get PASSED [ 18%] locust/test/test_fasthttp.py::TestFastHttpUserClass::test_client_get_absolute_url PASSED [ 18%] locust/test/test_fasthttp.py::TestFastHttpUserClass::test_client_head PASSED [ 18%] locust/test/test_fasthttp.py::TestFastHttpUserClass::test_client_pool_concurrency PASSED [ 18%] locust/test/test_fasthttp.py::TestFastHttpUserClass::test_client_pool_per_user_instance PASSED [ 18%] locust/test/test_fasthttp.py::TestFastHttpUserClass::test_client_post PASSED [ 18%] locust/test/test_fasthttp.py::TestFastHttpUserClass::test_client_put PASSED [ 19%] locust/test/test_fasthttp.py::TestFastHttpUserClass::test_client_request_headers PASSED [ 19%] locust/test/test_fasthttp.py::TestFastHttpUserClass::test_complex_content_type PASSED [ 19%] locust/test/test_fasthttp.py::TestFastHttpUserClass::test_get_request PASSED [ 19%] locust/test/test_fasthttp.py::TestFastHttpUserClass::test_is_abstract PASSED [ 19%] locust/test/test_fasthttp.py::TestFastHttpUserClass::test_log_request_name_argument PASSED [ 20%] locust/test/test_fasthttp.py::TestFastHttpUserClass::test_max_redirect_setting PASSED [ 20%] locust/test/test_fasthttp.py::TestFastHttpUserClass::test_network_timeout_setting PASSED [ 20%] locust/test/test_fasthttp.py::TestFastHttpUserClass::test_redirect_url_original_path_as_name PASSED [ 20%] locust/test/test_fasthttp.py::TestFastHttpUserClass::test_shared_client_pool PASSED [ 20%] locust/test/test_fasthttp.py::TestFastHttpUserClass::test_slow_redirect PASSED [ 20%] locust/test/test_fasthttp.py::TestFastHttpCatchResponse::test_catch_response PASSED [ 21%] locust/test/test_fasthttp.py::TestFastHttpCatchResponse::test_catch_response_allow_404 PASSED [ 21%] locust/test/test_fasthttp.py::TestFastHttpCatchResponse::test_catch_response_connection_error_fail PASSED [ 21%] locust/test/test_fasthttp.py::TestFastHttpCatchResponse::test_catch_response_connection_error_success PASSED [ 21%] locust/test/test_fasthttp.py::TestFastHttpCatchResponse::test_catch_response_http_fail PASSED [ 21%] locust/test/test_fasthttp.py::TestFastHttpCatchResponse::test_catch_response_http_manual_fail PASSED [ 22%] locust/test/test_fasthttp.py::TestFastHttpCatchResponse::test_catch_response_http_manual_success PASSED [ 22%] locust/test/test_fasthttp.py::TestFastHttpCatchResponse::test_catch_response_missing_with_block PASSED [ 22%] locust/test/test_fasthttp.py::TestFastHttpCatchResponse::test_interrupt_taskset_with_catch_response PASSED [ 22%] locust/test/test_fasthttp.py::TestFastHttpCatchResponse::test_missing_catch_response_true PASSED [ 22%] locust/test/test_fasthttp.py::TestFastHttpCatchResponse::test_rest_fail PASSED [ 22%] locust/test/test_fasthttp.py::TestFastHttpCatchResponse::test_rest_success PASSED [ 23%] locust/test/test_fasthttp.py::TestFastHttpSsl::test_ssl_request_insecure PASSED [ 23%] locust/test/test_http.py::TestHttpSession::test_catch_response_default_fail PASSED [ 23%] locust/test/test_http.py::TestHttpSession::test_catch_response_default_success PASSED [ 23%] locust/test/test_http.py::TestHttpSession::test_catch_response_fail_successful_request PASSED [ 23%] locust/test/test_http.py::TestHttpSession::test_catch_response_fail_successful_request_with_non_string_error_message PASSED [ 24%] locust/test/test_http.py::TestHttpSession::test_catch_response_missing_with_block PASSED [ 24%] locust/test/test_http.py::TestHttpSession::test_catch_response_multiple_failure_and_success PASSED [ 24%] locust/test/test_http.py::TestHttpSession::test_catch_response_pass_failed_request PASSED [ 24%] locust/test/test_http.py::TestHttpSession::test_catch_response_pass_failed_request_with_other_exception_within_block PASSED [ 24%] locust/test/test_http.py::TestHttpSession::test_catch_response_response_error PASSED [ 24%] locust/test/test_http.py::TestHttpSession::test_catch_response_timeout PASSED [ 25%] locust/test/test_http.py::TestHttpSession::test_catch_response_with_name_replacement PASSED [ 25%] locust/test/test_http.py::TestHttpSession::test_connection_error PASSED [ 25%] locust/test/test_http.py::TestHttpSession::test_context_in_success PASSED [ 25%] locust/test/test_http.py::TestHttpSession::test_cookie PASSED [ 25%] locust/test/test_http.py::TestHttpSession::test_delete PASSED [ 26%] locust/test/test_http.py::TestHttpSession::test_error_message PASSED [ 26%] locust/test/test_http.py::TestHttpSession::test_error_message_with_name_replacement PASSED [ 26%] locust/test/test_http.py::TestHttpSession::test_event_measure FAILED [ 26%] locust/test/test_http.py::TestHttpSession::test_get PASSED [ 26%] locust/test/test_http.py::TestHttpSession::test_get_with_params PASSED [ 26%] locust/test/test_http.py::TestHttpSession::test_head PASSED [ 27%] locust/test/test_http.py::TestHttpSession::test_missing_catch_response_true PASSED [ 27%] locust/test/test_http.py::TestHttpSession::test_options PASSED [ 27%] locust/test/test_http.py::TestHttpSession::test_post_redirect PASSED [ 27%] locust/test/test_http.py::TestHttpSession::test_response_parameter PASSED [ 27%] locust/test/test_http.py::TestHttpSession::test_slow_redirect PASSED [ 28%] locust/test/test_http.py::TestHttpSession::test_streaming_response PASSED [ 28%] locust/test/test_http.py::TestHttpSession::test_user_context PASSED [ 28%] locust/test/test_http.py::TestHttpSession::test_wrong_url PASSED [ 28%] locust/test/test_interruptable_task.py::TestInterruptableTask::test_interruptable_task PASSED [ 28%] locust/test/test_load_locustfile.py::TestLoadLocustfile::test_command_line_arguments_override_config_file PASSED [ 28%] locust/test/test_load_locustfile.py::TestLoadLocustfile::test_create_environment PASSED [ 29%] locust/test/test_load_locustfile.py::TestLoadLocustfile::test_is_user_class PASSED [ 29%] locust/test/test_load_locustfile.py::TestLoadLocustfile::test_load_locust_file_called_locust_dot_py PASSED [ 29%] locust/test/test_load_locustfile.py::TestLoadLocustfile::test_load_locust_file_from_absolute_path PASSED [ 29%] locust/test/test_load_locustfile.py::TestLoadLocustfile::test_load_locust_file_from_relative_path PASSED [ 29%] locust/test/test_load_locustfile.py::TestLoadLocustfile::test_load_locust_file_with_a_dot_in_filename PASSED [ 30%] locust/test/test_load_locustfile.py::TestLoadLocustfile::test_locustfile_can_be_set_in_config_file PASSED [ 30%] locust/test/test_load_locustfile.py::TestLoadLocustfile::test_locustfile_from_url FAILED [ 30%] locust/test/test_load_locustfile.py::TestLoadLocustfile::test_return_docstring_and_user_classes PASSED [ 30%] locust/test/test_load_locustfile.py::TestLoadLocustfile::test_specify_config_file PASSED [ 30%] locust/test/test_load_locustfile.py::TestLoadLocustfile::test_with_abstract_shape_class PASSED [ 30%] locust/test/test_load_locustfile.py::TestLoadLocustfile::test_with_multiple_shape_classes PASSED [ 31%] locust/test/test_load_locustfile.py::TestLoadLocustfile::test_with_not_imported_shape_class PASSED [ 31%] locust/test/test_load_locustfile.py::TestLoadLocustfile::test_with_shape_class PASSED [ 31%] locust/test/test_locust_class.py::TestTaskSet::test_on_start PASSED [ 31%] locust/test/test_locust_class.py::TestTaskSet::test_on_start_interrupt PASSED [ 31%] locust/test/test_locust_class.py::TestTaskSet::test_on_stop_interrupt PASSED [ 32%] locust/test/test_locust_class.py::TestTaskSet::test_on_stop_interrupt_reschedule PASSED [ 32%] locust/test/test_locust_class.py::TestTaskSet::test_on_stop_when_locust_stops PASSED [ 32%] locust/test/test_locust_class.py::TestTaskSet::test_parent_attribute PASSED [ 32%] locust/test/test_locust_class.py::TestTaskSet::test_schedule_task PASSED [ 32%] locust/test/test_locust_class.py::TestTaskSet::test_schedule_task_bound_method PASSED [ 32%] locust/test/test_locust_class.py::TestTaskSet::test_sub_taskset PASSED [ 33%] locust/test/test_locust_class.py::TestTaskSet::test_sub_taskset_tasks_decorator PASSED [ 33%] locust/test/test_locust_class.py::TestTaskSet::test_task_decorator_on_taskset PASSED [ 33%] locust/test/test_locust_class.py::TestTaskSet::test_task_decorator_ratio PASSED [ 33%] locust/test/test_locust_class.py::TestTaskSet::test_task_decorator_with_or_without_argument PASSED [ 33%] locust/test/test_locust_class.py::TestTaskSet::test_task_ratio PASSED [ 34%] locust/test/test_locust_class.py::TestTaskSet::test_tasks_missing_from_user_gives_user_friendly_exception PASSED [ 34%] locust/test/test_locust_class.py::TestTaskSet::test_tasks_missing_gives_user_friendly_exception PASSED [ 34%] locust/test/test_locust_class.py::TestTaskSet::test_tasks_on_abstract_locust PASSED [ 34%] locust/test/test_locust_class.py::TestTaskSet::test_tasks_on_locust PASSED [ 34%] locust/test/test_locust_class.py::TestTaskSet::test_taskset_inheritance PASSED [ 34%] locust/test/test_locust_class.py::TestTaskSet::test_taskset_on_abstract_locust PASSED [ 35%] locust/test/test_locust_class.py::TestTaskSet::test_user_is_read_only PASSED [ 35%] locust/test/test_locust_class.py::TestTaskSet::test_wait_function PASSED [ 35%] locust/test/test_locust_class.py::TestLocustClass::test_deprecated_locust_class PASSED [ 35%] locust/test/test_locust_class.py::TestLocustClass::test_locust_forced_stop PASSED [ 35%] locust/test/test_locust_class.py::TestLocustClass::test_locust_graceful_stop PASSED [ 36%] locust/test/test_locust_class.py::TestLocustClass::test_locust_on_start PASSED [ 36%] locust/test/test_locust_class.py::TestLocustClass::test_locust_on_stop PASSED [ 36%] locust/test/test_locust_class.py::TestLocustClass::test_locust_start PASSED [ 36%] locust/test/test_locust_class.py::TestLocustClass::test_locust_wait PASSED [ 36%] locust/test/test_locust_class.py::TestWebLocustClass::test_client_basic_auth PASSED [ 36%] locust/test/test_locust_class.py::TestWebLocustClass::test_client_delete PASSED [ 37%] locust/test/test_locust_class.py::TestWebLocustClass::test_client_get PASSED [ 37%] locust/test/test_locust_class.py::TestWebLocustClass::test_client_get_absolute_url PASSED [ 37%] locust/test/test_locust_class.py::TestWebLocustClass::test_client_head PASSED [ 37%] locust/test/test_locust_class.py::TestWebLocustClass::test_client_post PASSED [ 37%] locust/test/test_locust_class.py::TestWebLocustClass::test_client_put PASSED [ 38%] locust/test/test_locust_class.py::TestWebLocustClass::test_client_request_headers PASSED [ 38%] locust/test/test_locust_class.py::TestWebLocustClass::test_get_request PASSED [ 38%] locust/test/test_locust_class.py::TestWebLocustClass::test_log_request_name_argument PASSED [ 38%] locust/test/test_locust_class.py::TestWebLocustClass::test_redirect_url_original_path_as_name PASSED [ 38%] locust/test/test_locust_class.py::TestCatchResponse::test_catch_response PASSED [ 38%] locust/test/test_locust_class.py::TestCatchResponse::test_catch_response_allow_404 PASSED [ 39%] locust/test/test_locust_class.py::TestCatchResponse::test_catch_response_connection_error_fail PASSED [ 39%] locust/test/test_locust_class.py::TestCatchResponse::test_catch_response_connection_error_success PASSED [ 39%] locust/test/test_locust_class.py::TestCatchResponse::test_catch_response_http_fail PASSED [ 39%] locust/test/test_locust_class.py::TestCatchResponse::test_catch_response_http_manual_fail PASSED [ 39%] locust/test/test_locust_class.py::TestCatchResponse::test_catch_response_http_manual_success PASSED [ 40%] locust/test/test_locust_class.py::TestCatchResponse::test_interrupt_taskset_with_catch_response PASSED [ 40%] locust/test/test_log.py::TestGreenletExceptionLogger::test_greenlet_exception_logger PASSED [ 40%] locust/test/test_log.py::TestLoggingOptions::test_log_to_file FAILED [ 40%] locust/test/test_log.py::TestLoggingOptions::test_logging_output FAILED [ 40%] locust/test/test_log.py::TestLoggingOptions::test_skip_logging FAILED [ 40%] locust/test/test_log.py::TestLoggingOptions::test_user_broken_on_start FAILED [ 41%] locust/test/test_main.py::StandaloneIntegrationTests::test_autostart_multiple_locustfiles_with_shape FAILED [ 41%] locust/test/test_main.py::StandaloneIntegrationTests::test_autostart_w_load_shape FAILED [ 41%] locust/test/test_main.py::StandaloneIntegrationTests::test_autostart_w_run_time FAILED [ 41%] locust/test/test_main.py::StandaloneIntegrationTests::test_autostart_wo_run_time FAILED [ 41%] locust/test/test_main.py::StandaloneIntegrationTests::test_command_line_user_selection FAILED [ 42%] locust/test/test_main.py::StandaloneIntegrationTests::test_custom_arguments FAILED [ 42%] locust/test/test_main.py::StandaloneIntegrationTests::test_custom_arguments_in_file FAILED [ 42%] locust/test/test_main.py::StandaloneIntegrationTests::test_custom_exit_code FAILED [ 42%] locust/test/test_main.py::StandaloneIntegrationTests::test_default_headless_spawn_options FAILED [ 42%] locust/test/test_main.py::StandaloneIntegrationTests::test_default_headless_spawn_options_with_shape FAILED [ 42%] locust/test/test_main.py::StandaloneIntegrationTests::test_error_when_duplicate_shape_class_names FAILED [ 43%] locust/test/test_main.py::StandaloneIntegrationTests::test_error_when_duplicate_userclass_names FAILED [ 43%] locust/test/test_main.py::StandaloneIntegrationTests::test_error_when_locustfiles_directory_is_empty FAILED [ 43%] locust/test/test_main.py::StandaloneIntegrationTests::test_error_when_no_tasks_match_tags FAILED [ 43%] locust/test/test_main.py::StandaloneIntegrationTests::test_error_when_providing_both_run_time_and_a_shape_class FAILED [ 43%] locust/test/test_main.py::StandaloneIntegrationTests::test_graceful_exit_when_keyboard_interrupt FAILED [ 44%] locust/test/test_main.py::StandaloneIntegrationTests::test_headless_spawn_options_wo_run_time FAILED [ 44%] locust/test/test_main.py::StandaloneIntegrationTests::test_help_arg FAILED [ 44%] locust/test/test_main.py::StandaloneIntegrationTests::test_html_report_option FAILED [ 44%] locust/test/test_main.py::StandaloneIntegrationTests::test_input FAILED [ 44%] locust/test/test_main.py::StandaloneIntegrationTests::test_invalid_percentile_parameter FAILED [ 44%] locust/test/test_main.py::StandaloneIntegrationTests::test_invalid_stop_timeout_string FAILED [ 45%] locust/test/test_main.py::StandaloneIntegrationTests::test_no_error_when_same_userclass_in_two_files FAILED [ 45%] locust/test/test_main.py::StandaloneIntegrationTests::test_percentile_parameter FAILED [ 45%] locust/test/test_main.py::StandaloneIntegrationTests::test_percentiles_to_statistics FAILED [ 45%] locust/test/test_main.py::StandaloneIntegrationTests::test_run_autostart_with_multiple_locustfiles FAILED [ 45%] locust/test/test_main.py::StandaloneIntegrationTests::test_run_headless_with_multiple_locustfiles FAILED [ 46%] locust/test/test_main.py::StandaloneIntegrationTests::test_run_headless_with_multiple_locustfiles_with_shape FAILED [ 46%] locust/test/test_main.py::StandaloneIntegrationTests::test_run_with_userclass_picker FAILED [ 46%] locust/test/test_main.py::StandaloneIntegrationTests::test_shape_class_log_disabled_parameters FAILED [ 46%] locust/test/test_main.py::StandaloneIntegrationTests::test_shape_class_with_use_common_options FAILED [ 46%] locust/test/test_main.py::StandaloneIntegrationTests::test_spawing_with_fixed_multiple_locustfiles FAILED [ 46%] locust/test/test_main.py::StandaloneIntegrationTests::test_spawning_with_fixed FAILED [ 47%] locust/test/test_main.py::StandaloneIntegrationTests::test_web_options FAILED [ 47%] locust/test/test_main.py::StandaloneIntegrationTests::test_webserver FAILED [ 47%] locust/test/test_main.py::StandaloneIntegrationTests::test_webserver_multiple_locustfiles FAILED [ 47%] locust/test/test_main.py::StandaloneIntegrationTests::test_webserver_multiple_locustfiles_in_directory FAILED [ 47%] locust/test/test_main.py::StandaloneIntegrationTests::test_webserver_multiple_locustfiles_with_shape FAILED [ 48%] locust/test/test_main.py::DistributedIntegrationTests::test_distributed FAILED [ 48%] locust/test/test_main.py::DistributedIntegrationTests::test_distributed_events FAILED [ 48%] locust/test/test_main.py::DistributedIntegrationTests::test_distributed_report_timeout_expired FAILED [ 48%] locust/test/test_main.py::DistributedIntegrationTests::test_distributed_tags FAILED [ 48%] locust/test/test_main.py::DistributedIntegrationTests::test_distributed_with_locustfile_distribution_not_plain_filename FAILED [ 48%] locust/test/test_main.py::DistributedIntegrationTests::test_expect_workers FAILED [ 49%] locust/test/test_main.py::DistributedIntegrationTests::test_json_schema FAILED [ 49%] locust/test/test_main.py::DistributedIntegrationTests::test_locustfile_distribution FAILED [ 49%] locust/test/test_main.py::DistributedIntegrationTests::test_locustfile_distribution_with_workers_started_first FAILED [ 49%] locust/test/test_main.py::DistributedIntegrationTests::test_processes FAILED [ 49%] locust/test/test_main.py::DistributedIntegrationTests::test_processes_autodetect FAILED [ 50%] locust/test/test_main.py::DistributedIntegrationTests::test_processes_ctrl_c FAILED [ 50%] locust/test/test_main.py::DistributedIntegrationTests::test_processes_error_doesnt_blow_up_completely FAILED [ 50%] locust/test/test_main.py::DistributedIntegrationTests::test_processes_separate_worker FAILED [ 50%] locust/test/test_main.py::DistributedIntegrationTests::test_processes_workers_quit_unexpected FAILED [ 50%] locust/test/test_main.py::DistributedIntegrationTests::test_worker_indexes FAILED [ 51%] locust/test/test_main.py::DistributedIntegrationTests::test_workers_shut_down_if_master_is_gone FAILED [ 51%] locust/test/test_parser.py::TestParser::test_default PASSED [ 51%] locust/test/test_parser.py::TestParser::test_parse_options_from_conf_file PASSED [ 51%] locust/test/test_parser.py::TestParser::test_parse_options_from_toml_file PASSED [ 51%] locust/test/test_parser.py::TestParser::test_reset_stats PASSED [ 51%] locust/test/test_parser.py::TestParser::test_skip_log_setup PASSED [ 52%] locust/test/test_parser.py::TestArgumentParser::test_csv_full_history_requires_csv PASSED [ 52%] locust/test/test_parser.py::TestArgumentParser::test_custom_argument PASSED [ 52%] locust/test/test_parser.py::TestArgumentParser::test_custom_argument_help_message PASSED [ 52%] locust/test/test_parser.py::TestArgumentParser::test_custom_argument_included_in_web_ui PASSED [ 52%] locust/test/test_parser.py::TestArgumentParser::test_parse_locustfile PASSED [ 53%] locust/test/test_parser.py::TestArgumentParser::test_parse_locustfile_empty_directory_error PASSED [ 53%] locust/test/test_parser.py::TestArgumentParser::test_parse_locustfile_invalid_directory_error PASSED [ 53%] locust/test/test_parser.py::TestArgumentParser::test_parse_locustfile_multiple_files PASSED [ 53%] locust/test/test_parser.py::TestArgumentParser::test_parse_locustfile_with_directory PASSED [ 53%] locust/test/test_parser.py::TestArgumentParser::test_parse_locustfile_with_directory_ignores_invalid_filenames PASSED [ 53%] locust/test/test_parser.py::TestArgumentParser::test_parse_locustfile_with_nested_directory PASSED [ 54%] locust/test/test_parser.py::TestArgumentParser::test_parse_options PASSED [ 54%] locust/test/test_parser.py::TestArgumentParser::test_parse_options_from_env PASSED [ 54%] locust/test/test_parser.py::TestArgumentParser::test_unknown_command_line_arg PASSED [ 54%] locust/test/test_parser.py::TestFindLocustfiles::test_find_locustfiles_error_for_invalid_file_extension PASSED [ 54%] locust/test/test_parser.py::TestFindLocustfiles::test_find_locustfiles_error_if_directory_doesnt_exist PASSED [ 55%] locust/test/test_parser.py::TestFindLocustfiles::test_find_locustfiles_error_if_invalid_directory PASSED [ 55%] locust/test/test_parser.py::TestFindLocustfiles::test_find_locustfiles_error_if_multiple_values_for_directory PASSED [ 55%] locust/test/test_parser.py::TestFindLocustfiles::test_find_locustfiles_ignores_invalid_files_in_directory PASSED [ 55%] locust/test/test_parser.py::TestFindLocustfiles::test_find_locustfiles_with_is_directory PASSED [ 55%] locust/test/test_parser.py::TestFindLocustfiles::test_find_locustfiles_with_multiple_locustfiles PASSED [ 55%] locust/test/test_parser.py::TestLocustfileIsDirectory::test_locustfile_is_directory_false_if_file_and_directory_share_the_same_name PASSED [ 56%] locust/test/test_parser.py::TestLocustfileIsDirectory::test_locustfile_is_directory_multiple_locustfiles PASSED [ 56%] locust/test/test_parser.py::TestLocustfileIsDirectory::test_locustfile_is_directory_single_locustfile PASSED [ 56%] locust/test/test_parser.py::TestLocustfileIsDirectory::test_locustfile_is_directory_single_locustfile_without_file_extension PASSED [ 56%] locust/test/test_parser.py::TestLocustfileIsDirectory::test_locustfile_is_directory_true_if_directory PASSED [ 56%] locust/test/test_runners.py::TestLocustRunner::test_attributes_populated_when_calling_start PASSED [ 57%] locust/test/test_runners.py::TestLocustRunner::test_can_call_stop_endpoint_if_currently_swarming PASSED [ 57%] locust/test/test_runners.py::TestLocustRunner::test_change_user_count_during_spawning PASSED [ 57%] locust/test/test_runners.py::TestLocustRunner::test_cpu_warning FAILED [ 57%] locust/test/test_runners.py::TestLocustRunner::test_custom_dispatcher_class PASSED [ 57%] locust/test/test_runners.py::TestLocustRunner::test_custom_message PASSED [ 57%] locust/test/test_runners.py::TestLocustRunner::test_duplicate_message_handler_registration PASSED [ 58%] locust/test/test_runners.py::TestLocustRunner::test_host_class_attribute_from_web PASSED [ 58%] locust/test/test_runners.py::TestLocustRunner::test_kill_locusts PASSED [ 58%] locust/test/test_runners.py::TestLocustRunner::test_no_reset_stats PASSED [ 58%] locust/test/test_runners.py::TestLocustRunner::test_reset_stats PASSED [ 58%] locust/test/test_runners.py::TestLocustRunner::test_runner_quit_can_run_on_stop_for_multiple_users_concurrently PASSED [ 59%] locust/test/test_runners.py::TestLocustRunner::test_runner_reference_on_environment PASSED [ 59%] locust/test/test_runners.py::TestLocustRunner::test_start_event PASSED [ 59%] locust/test/test_runners.py::TestLocustRunner::test_stop_event PASSED [ 59%] locust/test/test_runners.py::TestLocustRunner::test_stop_event_quit PASSED [ 59%] locust/test/test_runners.py::TestLocustRunner::test_stop_event_stop_and_quit PASSED [ 59%] locust/test/test_runners.py::TestLocustRunner::test_stop_users_count PASSED [ 60%] locust/test/test_runners.py::TestLocustRunner::test_stop_users_with_spawn_rate FAILED [ 60%] locust/test/test_runners.py::TestLocustRunner::test_stopping_event PASSED [ 60%] locust/test/test_runners.py::TestLocustRunner::test_swarm_endpoint_is_non_blocking PASSED [ 60%] locust/test/test_runners.py::TestLocustRunner::test_target_user_count_is_set_before_ramp_up PASSED [ 60%] locust/test/test_runners.py::TestLocustRunner::test_undefined_custom_message PASSED [ 61%] locust/test/test_runners.py::TestLocustRunner::test_user_classes_count PASSED [ 61%] locust/test/test_runners.py::TestLocustRunner::test_user_count_starts_from_specified_amount_when_creating_new_test_after_previous_step_has_been_stopped PASSED [ 61%] locust/test/test_runners.py::TestLocustRunner::test_users_can_call_runner_quit_without_deadlocking PASSED [ 61%] locust/test/test_runners.py::TestMasterRunner::test_attributes_populated_when_calling_start FAILED [ 61%] locust/test/test_runners.py::TestMasterRunner::test_custom_message_receive PASSED [ 61%] locust/test/test_runners.py::TestMasterRunner::test_custom_message_send PASSED [ 62%] locust/test/test_runners.py::TestMasterRunner::test_custom_shape_scale_down FAILED [ 62%] locust/test/test_runners.py::TestMasterRunner::test_custom_shape_scale_interval FAILED [ 62%] locust/test/test_runners.py::TestMasterRunner::test_custom_shape_scale_up FAILED [ 62%] locust/test/test_runners.py::TestMasterRunner::test_exception_in_task PASSED [ 62%] locust/test/test_runners.py::TestMasterRunner::test_exception_is_caught PASSED [ 63%] locust/test/test_runners.py::TestMasterRunner::test_last_worker_missing_stops_test FAILED [ 63%] locust/test/test_runners.py::TestMasterRunner::test_last_worker_quitting_stops_test FAILED [ 63%] locust/test/test_runners.py::TestMasterRunner::test_master_current_response_times PASSED [ 63%] locust/test/test_runners.py::TestMasterRunner::test_master_discard_first_client_ready FAILED [ 63%] locust/test/test_runners.py::TestMasterRunner::test_master_marks_downed_workers_as_missing FAILED [ 63%] locust/test/test_runners.py::TestMasterRunner::test_master_reset_connection FAILED [ 64%] locust/test/test_runners.py::TestMasterRunner::test_master_total_stats PASSED [ 64%] locust/test/test_runners.py::TestMasterRunner::test_master_total_stats_with_none_response_times PASSED [ 64%] locust/test/test_runners.py::TestMasterRunner::test_rebalance_locust_users_on_worker_connect FAILED [ 64%] locust/test/test_runners.py::TestMasterRunner::test_reset_connection_after_RPCError FAILED [ 64%] locust/test/test_runners.py::TestMasterRunner::test_sends_spawn_data_to_ready_running_spawning_workers PASSED [ 65%] locust/test/test_runners.py::TestMasterRunner::test_spawn_correct_worker_indexes FAILED [ 65%] locust/test/test_runners.py::TestMasterRunner::test_spawn_fewer_locusts_than_workers FAILED [ 65%] locust/test/test_runners.py::TestMasterRunner::test_spawn_uneven_locusts FAILED [ 65%] locust/test/test_runners.py::TestMasterRunner::test_spawn_zero_locusts PASSED [ 65%] locust/test/test_runners.py::TestMasterRunner::test_start_event FAILED [ 65%] locust/test/test_runners.py::TestMasterRunner::test_stop_event FAILED [ 66%] locust/test/test_runners.py::TestMasterRunner::test_stop_event_quit FAILED [ 66%] locust/test/test_runners.py::TestMasterRunner::test_undefined_custom_message_receive PASSED [ 66%] locust/test/test_runners.py::TestMasterRunner::test_unknown_host_sends_message_to_master FAILED [ 66%] locust/test/test_runners.py::TestMasterRunner::test_wait_for_workers_report_after_ramp_up PASSED [ 66%] locust/test/test_runners.py::TestMasterRunner::test_worker_connect FAILED [ 67%] locust/test/test_runners.py::TestMasterRunner::test_worker_connect_with_special_versions FAILED [ 67%] locust/test/test_runners.py::TestMasterRunner::test_worker_missing_after_heartbeat_dead_interval FAILED [ 67%] locust/test/test_runners.py::TestMasterRunner::test_worker_sends_bad_message_to_master FAILED [ 67%] locust/test/test_runners.py::TestMasterRunner::test_worker_sends_unrecognized_message_to_master FAILED [ 67%] locust/test/test_runners.py::TestMasterRunner::test_worker_stats_report_median PASSED [ 67%] locust/test/test_runners.py::TestMasterRunner::test_worker_stats_report_with_none_response_times PASSED [ 68%] locust/test/test_runners.py::TestWorkerRunner::test_change_user_count_during_spawning PASSED [ 68%] locust/test/test_runners.py::TestWorkerRunner::test_computed_properties PASSED [ 68%] locust/test/test_runners.py::TestWorkerRunner::test_custom_message_receive PASSED [ 68%] locust/test/test_runners.py::TestWorkerRunner::test_custom_message_send PASSED [ 68%] locust/test/test_runners.py::TestWorkerRunner::test_reset_rpc_connection_to_master PASSED [ 69%] locust/test/test_runners.py::TestWorkerRunner::test_spawn_message_with_older_timestamp_is_rejected PASSED [ 69%] locust/test/test_runners.py::TestWorkerRunner::test_start_event PASSED [ 69%] locust/test/test_runners.py::TestWorkerRunner::test_stop_event PASSED [ 69%] locust/test/test_runners.py::TestWorkerRunner::test_undefined_custom_message_receive PASSED [ 69%] locust/test/test_runners.py::TestWorkerRunner::test_worker_connect_failure PASSED [ 69%] locust/test/test_runners.py::TestWorkerRunner::test_worker_connect_success PASSED [ 70%] locust/test/test_runners.py::TestWorkerRunner::test_worker_heartbeat_messages_sent_to_master PASSED [ 70%] locust/test/test_runners.py::TestWorkerRunner::test_worker_messages_sent_to_master PASSED [ 70%] locust/test/test_runners.py::TestWorkerRunner::test_worker_stop_timeout PASSED [ 70%] locust/test/test_runners.py::TestWorkerRunner::test_worker_without_stop_timeout PASSED [ 70%] locust/test/test_runners.py::TestMessageSerializing::test_message_serialize PASSED [ 71%] locust/test/test_runners.py::TestStopTimeout::test_gracefully_handle_exceptions_in_listener PASSED [ 71%] locust/test/test_runners.py::TestStopTimeout::test_kill_locusts_with_stop_timeout FAILED [ 71%] locust/test/test_runners.py::TestStopTimeout::test_stop_timeout FAILED [ 71%] locust/test/test_runners.py::TestStopTimeout::test_stop_timeout_during_on_start FAILED [ 71%] locust/test/test_runners.py::TestStopTimeout::test_stop_timeout_exit_during_wait PASSED [ 71%] locust/test/test_runners.py::TestStopTimeout::test_stop_timeout_with_interrupt PASSED [ 72%] locust/test/test_runners.py::TestStopTimeout::test_stop_timeout_with_interrupt_no_reschedule PASSED [ 72%] locust/test/test_runners.py::TestStopTimeout::test_stop_timeout_with_ramp_down PASSED [ 72%] locust/test/test_runners.py::TestStopTimeout::test_users_can_call_runner_quit_with_stop_timeout PASSED [ 72%] locust/test/test_sequential_taskset.py::TestTaskSet::test_task_sequence_multiple_iterations PASSED [ 72%] locust/test/test_sequential_taskset.py::TestTaskSet::test_task_sequence_with_inheritance PASSED [ 73%] locust/test/test_sequential_taskset.py::TestTaskSet::test_task_sequence_with_list PASSED [ 73%] locust/test/test_sequential_taskset.py::TestTaskSet::test_task_sequence_with_methods PASSED [ 73%] locust/test/test_sequential_taskset.py::TestTaskSet::test_task_sequence_with_methods_and_list PASSED [ 73%] locust/test/test_stats.py::TestRequestStats::test_aggregation PASSED [ 73%] locust/test/test_stats.py::TestRequestStats::test_aggregation_last_request_timestamp PASSED [ 73%] locust/test/test_stats.py::TestRequestStats::test_aggregation_min_response_time PASSED [ 74%] locust/test/test_stats.py::TestRequestStats::test_aggregation_with_decimal_rounding PASSED [ 74%] locust/test/test_stats.py::TestRequestStats::test_aggregation_with_rounding PASSED [ 74%] locust/test/test_stats.py::TestRequestStats::test_avg PASSED [ 74%] locust/test/test_stats.py::TestRequestStats::test_avg_only_none PASSED [ 74%] locust/test/test_stats.py::TestRequestStats::test_current_fail_per_sec PASSED [ 75%] locust/test/test_stats.py::TestRequestStats::test_current_rps PASSED [ 75%] locust/test/test_stats.py::TestRequestStats::test_custom_percentile_list PASSED [ 75%] locust/test/test_stats.py::TestRequestStats::test_error_grouping PASSED [ 75%] locust/test/test_stats.py::TestRequestStats::test_error_grouping_errors_with_memory_addresses PASSED [ 75%] locust/test/test_stats.py::TestRequestStats::test_median PASSED [ 75%] locust/test/test_stats.py::TestRequestStats::test_median_out_of_min_max_bounds PASSED [ 76%] locust/test/test_stats.py::TestRequestStats::test_num_reqs_fails PASSED [ 76%] locust/test/test_stats.py::TestRequestStats::test_percentile PASSED [ 76%] locust/test/test_stats.py::TestRequestStats::test_percentile_rounded_down PASSED [ 76%] locust/test/test_stats.py::TestRequestStats::test_percentile_rounded_up PASSED [ 76%] locust/test/test_stats.py::TestRequestStats::test_reset PASSED [ 77%] locust/test/test_stats.py::TestRequestStats::test_reset_min_response_time PASSED [ 77%] locust/test/test_stats.py::TestRequestStats::test_rps_less_than_one_second PASSED [ 77%] locust/test/test_stats.py::TestRequestStats::test_serialize_through_message PASSED [ 77%] locust/test/test_stats.py::TestRequestStats::test_total_content_length PASSED [ 77%] locust/test/test_stats.py::TestRequestStats::test_total_rps PASSED [ 77%] locust/test/test_stats.py::TestStatsPrinting::test_print_error_report PASSED [ 78%] locust/test/test_stats.py::TestStatsPrinting::test_print_percentile_stats PASSED [ 78%] locust/test/test_stats.py::TestStatsPrinting::test_print_stats PASSED [ 78%] locust/test/test_stats.py::TestCsvStats::test_csv_stats_on_master_from_aggregated_stats PASSED [ 78%] locust/test/test_stats.py::TestCsvStats::test_csv_stats_writer PASSED [ 78%] locust/test/test_stats.py::TestCsvStats::test_csv_stats_writer_full_history PASSED [ 79%] locust/test/test_stats.py::TestCsvStats::test_requests_csv_quote_escaping PASSED [ 79%] locust/test/test_stats.py::TestCsvStats::test_stats_history FAILED [ 79%] locust/test/test_stats.py::TestCsvStats::test_user_count_in_csv_history_stats FAILED [ 79%] locust/test/test_stats.py::TestCsvStats::test_write_csv_files PASSED [ 79%] locust/test/test_stats.py::TestCsvStats::test_write_csv_files_full_history PASSED [ 79%] locust/test/test_stats.py::TestStatsEntryResponseTimesCache::test_diff_response_times_dicts PASSED [ 80%] locust/test/test_stats.py::TestStatsEntryResponseTimesCache::test_get_current_response_time_percentile PASSED [ 80%] locust/test/test_stats.py::TestStatsEntryResponseTimesCache::test_get_current_response_time_percentile_outside_cache_window PASSED [ 80%] locust/test/test_stats.py::TestStatsEntryResponseTimesCache::test_latest_total_response_times_pruned PASSED [ 80%] locust/test/test_stats.py::TestStatsEntryResponseTimesCache::test_response_times_cached PASSED [ 80%] locust/test/test_stats.py::TestStatsEntryResponseTimesCache::test_response_times_not_cached_if_not_enabled PASSED [ 81%] locust/test/test_stats.py::TestStatsEntry::test_fail_ratio_with_all_failures PASSED [ 81%] locust/test/test_stats.py::TestStatsEntry::test_fail_ratio_with_half_failures PASSED [ 81%] locust/test/test_stats.py::TestStatsEntry::test_fail_ratio_with_no_failures PASSED [ 81%] locust/test/test_stats.py::TestRequestStatsWithWebserver::test_request_connection_error PASSED [ 81%] locust/test/test_stats.py::TestRequestStatsWithWebserver::test_request_stats_content_length PASSED [ 81%] locust/test/test_stats.py::TestRequestStatsWithWebserver::test_request_stats_named_endpoint PASSED [ 82%] locust/test/test_stats.py::TestRequestStatsWithWebserver::test_request_stats_named_endpoint_rename_request PASSED [ 82%] locust/test/test_stats.py::TestRequestStatsWithWebserver::test_request_stats_named_endpoint_request_name PASSED [ 82%] locust/test/test_stats.py::TestRequestStatsWithWebserver::test_request_stats_no_content_length PASSED [ 82%] locust/test/test_stats.py::TestRequestStatsWithWebserver::test_request_stats_no_content_length_streaming PASSED [ 82%] locust/test/test_stats.py::TestRequestStatsWithWebserver::test_request_stats_put PASSED [ 83%] locust/test/test_stats.py::TestRequestStatsWithWebserver::test_request_stats_query_variables PASSED [ 83%] locust/test/test_stats.py::TestInspectUser::test_get_task_ratio_relative PASSED [ 83%] locust/test/test_stats.py::TestInspectUser::test_get_task_ratio_total PASSED [ 83%] locust/test/test_tags.py::TestTags::test_env_exclude_tags PASSED [ 83%] locust/test/test_tags.py::TestTags::test_env_include_tags PASSED [ 83%] locust/test/test_tags.py::TestTags::test_exclude_tags_under_user PASSED [ 84%] locust/test/test_tags.py::TestTags::test_excluding_tags PASSED [ 84%] locust/test/test_tags.py::TestTags::test_excluding_tags_with_weights PASSED [ 84%] locust/test/test_tags.py::TestTags::test_excluding_tasksets PASSED [ 84%] locust/test/test_tags.py::TestTags::test_include_tags_under_user PASSED [ 84%] locust/test/test_tags.py::TestTags::test_including_and_excluding PASSED [ 85%] locust/test/test_tags.py::TestTags::test_including_tags PASSED [ 85%] locust/test/test_tags.py::TestTags::test_including_tags_with_weights PASSED [ 85%] locust/test/test_tags.py::TestTags::test_including_tasksets PASSED [ 85%] locust/test/test_tags.py::TestTags::test_tagged_tasks_shared_across_tasksets PASSED [ 85%] locust/test/test_tags.py::TestTags::test_tagging PASSED [ 85%] locust/test/test_tags.py::TestTags::test_tagging_taskset PASSED [ 86%] locust/test/test_tags.py::TestTags::test_tagging_without_args_fails PASSED [ 86%] locust/test/test_taskratio.py::TestTaskRatio::test_task_ratio_command PASSED [ 86%] locust/test/test_taskratio.py::TestTaskRatio::test_task_ratio_command_with_locust_weight PASSED [ 86%] locust/test/test_users.py::TestUserClass::test_fullname_class_scoped PASSED [ 86%] locust/test/test_users.py::TestUserClass::test_fullname_function_scoped PASSED [ 87%] locust/test/test_users.py::TestUserClass::test_fullname_module_scoped PASSED [ 87%] locust/test/test_users.py::TestHttpUserWithWebserver::test_pool_manager_per_user_instance PASSED [ 87%] locust/test/test_users.py::TestHttpUserWithWebserver::test_shared_pool_manager PASSED [ 87%] locust/test/test_util.py::TestParseTimespan::test_parse_timespan PASSED [ 87%] locust/test/test_util.py::TestParseTimespan::test_parse_timespan_invalid_values PASSED [ 87%] locust/test/test_util.py::TestRounding::test_rounding_down PASSED [ 88%] locust/test/test_util.py::TestRounding::test_rounding_up PASSED [ 88%] locust/test/test_wait_time.py::TestWaitTime::test_between PASSED [ 88%] locust/test/test_wait_time.py::TestWaitTime::test_constant PASSED [ 88%] locust/test/test_wait_time.py::TestWaitTime::test_constant_throughput FAILED [ 88%] locust/test/test_wait_time.py::TestWaitTime::test_default_wait_time PASSED [ 89%] locust/test/test_web.py::TestWebUI::test_custom_argument_dropdown PASSED [ 89%] locust/test/test_web.py::TestWebUI::test_custom_shape_deactivate_num_users_and_spawn_rate PASSED [ 89%] locust/test/test_web.py::TestWebUI::test_custom_shape_with_use_common_options_keep_num_users_and_spawn_rate PASSED [ 89%] locust/test/test_web.py::TestWebUI::test_exceptions PASSED [ 89%] locust/test/test_web.py::TestWebUI::test_exceptions_csv PASSED [ 89%] locust/test/test_web.py::TestWebUI::test_failure_stats_csv PASSED [ 90%] locust/test/test_web.py::TestWebUI::test_host_value_from_multiple_user_classes PASSED [ 90%] locust/test/test_web.py::TestWebUI::test_host_value_from_multiple_user_classes_different_hosts PASSED [ 90%] locust/test/test_web.py::TestWebUI::test_host_value_from_user_class PASSED [ 90%] locust/test/test_web.py::TestWebUI::test_html_stats_report PASSED [ 90%] locust/test/test_web.py::TestWebUI::test_index PASSED [ 91%] locust/test/test_web.py::TestWebUI::test_index_with_spawn_options PASSED [ 91%] locust/test/test_web.py::TestWebUI::test_logs PASSED [ 91%] locust/test/test_web.py::TestWebUI::test_report_download PASSED [ 91%] locust/test/test_web.py::TestWebUI::test_report_exceptions PASSED [ 91%] locust/test/test_web.py::TestWebUI::test_report_host PASSED [ 91%] locust/test/test_web.py::TestWebUI::test_report_host2 PASSED [ 92%] locust/test/test_web.py::TestWebUI::test_report_page PASSED [ 92%] locust/test/test_web.py::TestWebUI::test_report_page_empty_stats PASSED [ 92%] locust/test/test_web.py::TestWebUI::test_request_stats_csv PASSED [ 92%] locust/test/test_web.py::TestWebUI::test_request_stats_full_history_csv_not_present PASSED [ 92%] locust/test/test_web.py::TestWebUI::test_request_stats_with_errors PASSED [ 93%] locust/test/test_web.py::TestWebUI::test_reset_stats PASSED [ 93%] locust/test/test_web.py::TestWebUI::test_stats PASSED [ 93%] locust/test/test_web.py::TestWebUI::test_stats_cache PASSED [ 93%] locust/test/test_web.py::TestWebUI::test_stats_no_data PASSED [ 93%] locust/test/test_web.py::TestWebUI::test_stats_rounding PASSED [ 93%] locust/test/test_web.py::TestWebUI::test_swarm_custom_argument PASSED [ 94%] locust/test/test_web.py::TestWebUI::test_swarm_defaults_to_all_available_userclasses_when_userclass_picker_is_active_and_no_userclass_in_payload PASSED [ 94%] locust/test/test_web.py::TestWebUI::test_swarm_error_when_userclass_picker_is_active_but_no_available_userclasses PASSED [ 94%] locust/test/test_web.py::TestWebUI::test_swarm_host_value_not_specified PASSED [ 94%] locust/test/test_web.py::TestWebUI::test_swarm_host_value_specified PASSED [ 94%] locust/test/test_web.py::TestWebUI::test_swarm_multiple_userclasses_specified PASSED [ 95%] locust/test/test_web.py::TestWebUI::test_swarm_run_time PASSED [ 95%] locust/test/test_web.py::TestWebUI::test_swarm_run_time_empty_input PASSED [ 95%] locust/test/test_web.py::TestWebUI::test_swarm_run_time_invalid_input PASSED [ 95%] locust/test/test_web.py::TestWebUI::test_swarm_shape_class_defaults_to_none_when_userclass_picker_is_active PASSED [ 95%] locust/test/test_web.py::TestWebUI::test_swarm_shape_class_is_updated_when_userclass_picker_is_active PASSED [ 95%] locust/test/test_web.py::TestWebUI::test_swarm_shape_class_specified PASSED [ 96%] locust/test/test_web.py::TestWebUI::test_swarm_updates_parsed_options_when_multiple_userclasses_specified PASSED [ 96%] locust/test/test_web.py::TestWebUI::test_swarm_updates_parsed_options_when_single_userclass_specified PASSED [ 96%] locust/test/test_web.py::TestWebUI::test_swarm_userclass_shapeclass_ignored_when_userclass_picker_is_inactive PASSED [ 96%] locust/test/test_web.py::TestWebUI::test_swarm_userclass_specified PASSED [ 96%] locust/test/test_web.py::TestWebUI::test_swarm_uses_pre_selected_user_classes_when_empty_payload_and_test_is_already_running_with_class_picker PASSED [ 97%] locust/test/test_web.py::TestWebUI::test_template_args PASSED [ 97%] locust/test/test_web.py::TestWebUI::test_update_user_endpoint PASSED [ 97%] locust/test/test_web.py::TestWebUI::test_web_ui_no_runner PASSED [ 97%] locust/test/test_web.py::TestWebUI::test_web_ui_reference_on_environment PASSED [ 97%] locust/test/test_web.py::TestWebUIAuth::test_index_with_web_login_enabled_no_user PASSED [ 97%] locust/test/test_web.py::TestWebUIAuth::test_index_with_web_login_enabled_valid_user PASSED [ 98%] locust/test/test_web.py::TestWebUIWithTLS::test_index_with_https PASSED [ 98%] locust/test/test_web.py::TestWebUIFullHistory::test_request_stats_full_history_csv PASSED [ 98%] locust/test/test_web.py::TestModernWebUI::test_html_stats_report PASSED [ 98%] locust/test/test_web.py::TestModernWebUI::test_index_with_modern_ui PASSED [ 98%] locust/test/test_web.py::TestModernWebUI::test_web_ui_no_runner PASSED [ 99%] locust/test/test_zmqrpc.py::ZMQRPC_tests::test_client_recv PASSED [ 99%] locust/test/test_zmqrpc.py::ZMQRPC_tests::test_client_retry PASSED [ 99%] locust/test/test_zmqrpc.py::ZMQRPC_tests::test_client_send PASSED [ 99%] locust/test/test_zmqrpc.py::ZMQRPC_tests::test_constructor PASSED [ 99%] locust/test/test_zmqrpc.py::ZMQRPC_tests::test_rpc_error PASSED [100%] =================================== FAILURES =================================== ______________________ TestHttpSession.test_event_measure ______________________ self = def test_event_measure(self): kwargs = {} def on_request(**kw): kwargs.update(**kw) self.environment.events.request.add_listener(on_request) with self.environment.events.request.measure("GET", "/test") as request_meta: time.sleep(0.001) > self.assertTrue(1 <= kwargs["response_time"] <= 1.5, kwargs["response_time"]) E AssertionError: False is not true : 3.9539409990538843 locust/test/test_http.py:293: AssertionError _________________ TestLoadLocustfile.test_locustfile_from_url __________________ self = def _new_conn(self): """Establish a socket connection and set nodelay settings on it. :return: New socket connection. """ extra_kw = {} if self.source_address: extra_kw["source_address"] = self.source_address if self.socket_options: extra_kw["socket_options"] = self.socket_options try: > conn = connection.create_connection( (self._dns_host, self.port), self.timeout, **extra_kw ) /usr/lib/python3/dist-packages/urllib3/connection.py:174: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3/dist-packages/urllib3/util/connection.py:73: in create_connection for res in socket.getaddrinfo(host, port, family, socket.SOCK_STREAM): /usr/lib/python3/dist-packages/gevent/_socketcommon.py:225: in getaddrinfo addrlist = get_hub().resolver.getaddrinfo(host, port, family, type, proto, flags) /usr/lib/python3/dist-packages/gevent/resolver/thread.py:63: in getaddrinfo return self.pool.apply(_socket.getaddrinfo, args, kwargs) /usr/lib/python3/dist-packages/gevent/pool.py:161: in apply return self.spawn(func, *args, **kwds).get() src/gevent/event.py:329: in gevent._gevent_cevent.AsyncResult.get ??? src/gevent/event.py:359: in gevent._gevent_cevent.AsyncResult.get ??? src/gevent/event.py:347: in gevent._gevent_cevent.AsyncResult.get ??? src/gevent/event.py:327: in gevent._gevent_cevent.AsyncResult._raise_exception ??? /usr/lib/python3/dist-packages/gevent/_compat.py:49: in reraise raise value.with_traceback(tb) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ # Copyright (c) 2012 Denis Bilenko. See LICENSE for details. from __future__ import absolute_import from __future__ import division from __future__ import print_function import os import sys from greenlet import greenlet as RawGreenlet from gevent import monkey from gevent._compat import integer_types from gevent.event import AsyncResult from gevent.exceptions import InvalidThreadUseError from gevent.greenlet import Greenlet from gevent._hub_local import get_hub_if_exists from gevent.hub import _get_hub_noargs as get_hub from gevent.hub import getcurrent from gevent.hub import sleep from gevent.lock import Semaphore from gevent.pool import GroupMappingMixin from gevent.util import clear_stack_frames from gevent._threading import Queue from gevent._threading import EmptyTimeout from gevent._threading import start_new_thread from gevent._threading import get_thread_ident __all__ = [ 'ThreadPool', 'ThreadResult', ] def _format_hub(hub): if hub is None: return '' return '<%s at 0x%x thread_ident=0x%x>' % ( hub.__class__.__name__, id(hub), hub.thread_ident ) def _get_thread_profile(_sys=sys): if 'threading' in _sys.modules: return _sys.modules['threading']._profile_hook def _get_thread_trace(_sys=sys): if 'threading' in _sys.modules: return _sys.modules['threading']._trace_hook class _WorkerGreenlet(RawGreenlet): # Exists to produce a more useful repr for worker pool # threads/greenlets, and manage the communication of the worker # thread with the threadpool. # Inform the gevent.util.GreenletTree that this should be # considered the root (for printing purposes) greenlet_tree_is_root = True _thread_ident = 0 _exc_info = sys.exc_info _get_hub_if_exists = staticmethod(get_hub_if_exists) # We capture the hub each time through the loop in case its created # so we can destroy it after a fork. _hub_of_worker = None # The hub of the threadpool we're working for. Just for info. _hub = None # A cookie passed to task_queue.get() _task_queue_cookie = None # If not -1, how long to block waiting for a task before we # exit. _idle_task_timeout = -1 def __init__(self, threadpool): # Construct in the main thread (owner of the threadpool) # The parent greenlet and thread identifier will be set once the # new thread begins running. RawGreenlet.__init__(self) self._hub = threadpool.hub # Avoid doing any imports in the background thread if it's not # necessary (monkey.get_original imports if not patched). # Background imports can hang Python 2 (gevent's thread resolver runs in the BG, # and resolving may have to import the idna module, which needs an import lock, so # resolving at module scope) if monkey.is_module_patched('sys'): stderr = monkey.get_original('sys', 'stderr') else: stderr = sys.stderr self._stderr = stderr # We can capture the task_queue; even though it can change if the threadpool # is re-innitted, we won't be running in that case self._task_queue = threadpool.task_queue # type:gevent._threading.Queue self._task_queue_cookie = self._task_queue.allocate_cookie() self._unregister_worker = threadpool._unregister_worker self._idle_task_timeout = threadpool._idle_task_timeout threadpool._register_worker(self) try: start_new_thread(self._begin, ()) except: self._unregister_worker(self) raise def _begin(self, _get_c=getcurrent, _get_ti=get_thread_ident): # Pass arguments to avoid accessing globals during module shutdown. # we're in the new thread (but its root greenlet). Establish invariants and get going # by making this the current greenlet. self.parent = _get_c() # pylint:disable=attribute-defined-outside-init self._thread_ident = _get_ti() # ignore the parent attribute. (We can't set parent to None.) self.parent.greenlet_tree_is_ignored = True try: self.switch() # goto run() except: # pylint:disable=bare-except # run() will attempt to print any exceptions, but that might # not work during shutdown. sys.excepthook and such may be gone, # so things might not get printed at all except for a cryptic # message. This is especially true on Python 2 (doesn't seem to be # an issue on Python 3). pass def __fixup_hub_before_block(self): hub = self._get_hub_if_exists() # Don't create one; only set if a worker function did it if hub is not None: hub.name = 'ThreadPool Worker Hub' # While we block, don't let the monitoring thread, if any, # report us as blocked. Indeed, so long as we never # try to switch greenlets, don't report us as blocked--- # the threadpool is *meant* to run blocking tasks if hub is not None and hub.periodic_monitoring_thread is not None: hub.periodic_monitoring_thread.ignore_current_greenlet_blocking() self._hub_of_worker = hub @staticmethod def __print_tb(tb, stderr): # Extracted from traceback to avoid accessing any module # globals (these sometimes happen during interpreter shutdown; # see test__subprocess_interrupted) while tb is not None: f = tb.tb_frame lineno = tb.tb_lineno co = f.f_code filename = co.co_filename name = co.co_name print(' File "%s", line %d, in %s' % (filename, lineno, name), file=stderr) tb = tb.tb_next def _before_run_task(self, func, args, kwargs, thread_result, _sys=sys, _get_thread_profile=_get_thread_profile, _get_thread_trace=_get_thread_trace): # pylint:disable=unused-argument _sys.setprofile(_get_thread_profile()) _sys.settrace(_get_thread_trace()) def _after_run_task(self, func, args, kwargs, thread_result, _sys=sys): # pylint:disable=unused-argument _sys.setprofile(None) _sys.settrace(None) def __run_task(self, func, args, kwargs, thread_result): self._before_run_task(func, args, kwargs, thread_result) try: > thread_result.set(func(*args, **kwargs)) E socket.gaierror: [Errno -3] Temporary failure in name resolution /usr/lib/python3/dist-packages/gevent/threadpool.py:173: gaierror During handling of the above exception, another exception occurred: self = method = 'GET', url = '/locustio/locust/master/examples/basic.py', body = None headers = {'User-Agent': 'python-requests/2.31.0', 'Accept-Encoding': 'gzip, deflate, br', 'Accept': '*/*', 'Connection': 'keep-alive'} retries = Retry(total=0, connect=None, read=False, redirect=None, status=None) redirect = False, assert_same_host = False timeout = Timeout(connect=None, read=None, total=None), pool_timeout = None release_conn = False, chunked = False, body_pos = None response_kw = {'decode_content': False, 'preload_content': False} parsed_url = Url(scheme=None, auth=None, host=None, port=None, path='/locustio/locust/master/examples/basic.py', query=None, fragment=None) destination_scheme = None, conn = None, release_this_conn = True http_tunnel_required = False, err = None, clean_exit = False def urlopen( self, method, url, body=None, headers=None, retries=None, redirect=True, assert_same_host=True, timeout=_Default, pool_timeout=None, release_conn=None, chunked=False, body_pos=None, **response_kw ): """ Get a connection from the pool and perform an HTTP request. This is the lowest level call for making a request, so you'll need to specify all the raw details. .. note:: More commonly, it's appropriate to use a convenience method provided by :class:`.RequestMethods`, such as :meth:`request`. .. note:: `release_conn` will only behave as expected if `preload_content=False` because we want to make `preload_content=False` the default behaviour someday soon without breaking backwards compatibility. :param method: HTTP request method (such as GET, POST, PUT, etc.) :param url: The URL to perform the request on. :param body: Data to send in the request body, either :class:`str`, :class:`bytes`, an iterable of :class:`str`/:class:`bytes`, or a file-like object. :param headers: Dictionary of custom headers to send, such as User-Agent, If-None-Match, etc. If None, pool headers are used. If provided, these headers completely replace any pool-specific headers. :param retries: Configure the number of retries to allow before raising a :class:`~urllib3.exceptions.MaxRetryError` exception. Pass ``None`` to retry until you receive a response. Pass a :class:`~urllib3.util.retry.Retry` object for fine-grained control over different types of retries. Pass an integer number to retry connection errors that many times, but no other types of errors. Pass zero to never retry. If ``False``, then retries are disabled and any exception is raised immediately. Also, instead of raising a MaxRetryError on redirects, the redirect response will be returned. :type retries: :class:`~urllib3.util.retry.Retry`, False, or an int. :param redirect: If True, automatically handle redirects (status codes 301, 302, 303, 307, 308). Each redirect counts as a retry. Disabling retries will disable redirect, too. :param assert_same_host: If ``True``, will make sure that the host of the pool requests is consistent else will raise HostChangedError. When ``False``, you can use the pool on an HTTP proxy and request foreign hosts. :param timeout: If specified, overrides the default timeout for this one request. It may be a float (in seconds) or an instance of :class:`urllib3.util.Timeout`. :param pool_timeout: If set and the pool is set to block=True, then this method will block for ``pool_timeout`` seconds and raise EmptyPoolError if no connection is available within the time period. :param release_conn: If False, then the urlopen call will not release the connection back into the pool once a response is received (but will release if you read the entire contents of the response such as when `preload_content=True`). This is useful if you're not preloading the response's content immediately. You will need to call ``r.release_conn()`` on the response ``r`` to return the connection back into the pool. If None, it takes the value of ``response_kw.get('preload_content', True)``. :param chunked: If True, urllib3 will send the body using chunked transfer encoding. Otherwise, urllib3 will send the body using the standard content-length form. Defaults to False. :param int body_pos: Position to seek to in file-like body in the event of a retry or redirect. Typically this won't need to be set because urllib3 will auto-populate the value when needed. :param \\**response_kw: Additional parameters are passed to :meth:`urllib3.response.HTTPResponse.from_httplib` """ parsed_url = parse_url(url) destination_scheme = parsed_url.scheme if headers is None: headers = self.headers if not isinstance(retries, Retry): retries = Retry.from_int(retries, redirect=redirect, default=self.retries) if release_conn is None: release_conn = response_kw.get("preload_content", True) # Check host if assert_same_host and not self.is_same_host(url): raise HostChangedError(self, url, retries) # Ensure that the URL we're connecting to is properly encoded if url.startswith("/"): url = six.ensure_str(_encode_target(url)) else: url = six.ensure_str(parsed_url.url) conn = None # Track whether `conn` needs to be released before # returning/raising/recursing. Update this variable if necessary, and # leave `release_conn` constant throughout the function. That way, if # the function recurses, the original value of `release_conn` will be # passed down into the recursive call, and its value will be respected. # # See issue #651 [1] for details. # # [1] release_this_conn = release_conn http_tunnel_required = connection_requires_http_tunnel( self.proxy, self.proxy_config, destination_scheme ) # Merge the proxy headers. Only done when not using HTTP CONNECT. We # have to copy the headers dict so we can safely change it without those # changes being reflected in anyone else's copy. if not http_tunnel_required: headers = headers.copy() headers.update(self.proxy_headers) # Must keep the exception bound to a separate variable or else Python 3 # complains about UnboundLocalError. err = None # Keep track of whether we cleanly exited the except block. This # ensures we do proper cleanup in finally. clean_exit = False # Rewind body position, if needed. Record current position # for future rewinds in the event of a redirect/retry. body_pos = set_file_position(body, body_pos) try: # Request a connection from the queue. timeout_obj = self._get_timeout(timeout) conn = self._get_conn(timeout=pool_timeout) conn.timeout = timeout_obj.connect_timeout is_new_proxy_conn = self.proxy is not None and not getattr( conn, "sock", None ) if is_new_proxy_conn and http_tunnel_required: self._prepare_proxy(conn) # Make the request on the httplib connection object. > httplib_response = self._make_request( conn, method, url, timeout=timeout_obj, body=body, headers=headers, chunked=chunked, ) /usr/lib/python3/dist-packages/urllib3/connectionpool.py:716: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3/dist-packages/urllib3/connectionpool.py:405: in _make_request self._validate_conn(conn) /usr/lib/python3/dist-packages/urllib3/connectionpool.py:1059: in _validate_conn conn.connect() /usr/lib/python3/dist-packages/urllib3/connection.py:363: in connect self.sock = conn = self._new_conn() _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = def _new_conn(self): """Establish a socket connection and set nodelay settings on it. :return: New socket connection. """ extra_kw = {} if self.source_address: extra_kw["source_address"] = self.source_address if self.socket_options: extra_kw["socket_options"] = self.socket_options try: conn = connection.create_connection( (self._dns_host, self.port), self.timeout, **extra_kw ) except SocketTimeout: raise ConnectTimeoutError( self, "Connection to %s timed out. (connect timeout=%s)" % (self.host, self.timeout), ) except SocketError as e: > raise NewConnectionError( self, "Failed to establish a new connection: %s" % e ) E urllib3.exceptions.NewConnectionError: : Failed to establish a new connection: [Errno -3] Temporary failure in name resolution /usr/lib/python3/dist-packages/urllib3/connection.py:186: NewConnectionError During handling of the above exception, another exception occurred: self = request = , stream = False timeout = Timeout(connect=None, read=None, total=None), verify = True cert = None, proxies = OrderedDict([('no', 'localhost')]) def send( self, request, stream=False, timeout=None, verify=True, cert=None, proxies=None ): """Sends PreparedRequest object. Returns Response object. :param request: The :class:`PreparedRequest ` being sent. :param stream: (optional) Whether to stream the request content. :param timeout: (optional) How long to wait for the server to send data before giving up, as a float, or a :ref:`(connect timeout, read timeout) ` tuple. :type timeout: float or tuple or urllib3 Timeout object :param verify: (optional) Either a boolean, in which case it controls whether we verify the server's TLS certificate, or a string, in which case it must be a path to a CA bundle to use :param cert: (optional) Any user-provided SSL certificate to be trusted. :param proxies: (optional) The proxies dictionary to apply to the request. :rtype: requests.Response """ try: conn = self.get_connection(request.url, proxies) except LocationValueError as e: raise InvalidURL(e, request=request) self.cert_verify(conn, request.url, verify, cert) url = self.request_url(request, proxies) self.add_headers( request, stream=stream, timeout=timeout, verify=verify, cert=cert, proxies=proxies, ) chunked = not (request.body is None or "Content-Length" in request.headers) if isinstance(timeout, tuple): try: connect, read = timeout timeout = TimeoutSauce(connect=connect, read=read) except ValueError: raise ValueError( f"Invalid timeout {timeout}. Pass a (connect, read) timeout tuple, " f"or a single float to set both timeouts to the same value." ) elif isinstance(timeout, TimeoutSauce): pass else: timeout = TimeoutSauce(connect=timeout, read=timeout) try: > resp = conn.urlopen( method=request.method, url=url, body=request.body, headers=request.headers, redirect=False, assert_same_host=False, preload_content=False, decode_content=False, retries=self.max_retries, timeout=timeout, chunked=chunked, ) /usr/lib/python3/dist-packages/requests/adapters.py:486: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3/dist-packages/urllib3/connectionpool.py:800: in urlopen retries = retries.increment( _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = Retry(total=0, connect=None, read=False, redirect=None, status=None) method = 'GET', url = '/locustio/locust/master/examples/basic.py' response = None error = NewConnectionError(': Failed to establish a new connection: [Errno -3] Temporary failure in name resolution') _pool = _stacktrace = def increment( self, method=None, url=None, response=None, error=None, _pool=None, _stacktrace=None, ): """Return a new Retry object with incremented retry counters. :param response: A response object, or None, if the server did not return a response. :type response: :class:`~urllib3.response.HTTPResponse` :param Exception error: An error encountered during the request, or None if the response was received successfully. :return: A new ``Retry`` object. """ if self.total is False and error: # Disabled, indicate to re-raise the error. raise six.reraise(type(error), error, _stacktrace) total = self.total if total is not None: total -= 1 connect = self.connect read = self.read redirect = self.redirect status_count = self.status other = self.other cause = "unknown" status = None redirect_location = None if error and self._is_connection_error(error): # Connect retry? if connect is False: raise six.reraise(type(error), error, _stacktrace) elif connect is not None: connect -= 1 elif error and self._is_read_error(error): # Read retry? if read is False or not self._is_method_retryable(method): raise six.reraise(type(error), error, _stacktrace) elif read is not None: read -= 1 elif error: # Other retry? if other is not None: other -= 1 elif response and response.get_redirect_location(): # Redirect retry? if redirect is not None: redirect -= 1 cause = "too many redirects" redirect_location = response.get_redirect_location() status = response.status else: # Incrementing because of a server error like a 500 in # status_forcelist and the given method is in the allowed_methods cause = ResponseError.GENERIC_ERROR if response and response.status: if status_count is not None: status_count -= 1 cause = ResponseError.SPECIFIC_ERROR.format(status_code=response.status) status = response.status history = self.history + ( RequestHistory(method, url, error, status, redirect_location), ) new_retry = self.new( total=total, connect=connect, read=read, redirect=redirect, status=status_count, other=other, history=history, ) if new_retry.is_exhausted(): > raise MaxRetryError(_pool, url, error or ResponseError(cause)) E urllib3.exceptions.MaxRetryError: HTTPSConnectionPool(host='raw.githubusercontent.com', port=443): Max retries exceeded with url: /locustio/locust/master/examples/basic.py (Caused by NewConnectionError(': Failed to establish a new connection: [Errno -3] Temporary failure in name resolution')) /usr/lib/python3/dist-packages/urllib3/util/retry.py:592: MaxRetryError During handling of the above exception, another exception occurred: url = 'https://raw.githubusercontent.com/locustio/locust/master/examples/basic.py' def download_locustfile_from_url(url: str) -> str: try: > response = requests.get(url) locust/argument_parser.py:193: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3/dist-packages/requests/api.py:73: in get return request("get", url, params=params, **kwargs) /usr/lib/python3/dist-packages/requests/api.py:59: in request return session.request(method=method, url=url, **kwargs) /usr/lib/python3/dist-packages/requests/sessions.py:589: in request resp = self.send(prep, **send_kwargs) /usr/lib/python3/dist-packages/requests/sessions.py:703: in send r = adapter.send(request, **kwargs) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = request = , stream = False timeout = Timeout(connect=None, read=None, total=None), verify = True cert = None, proxies = OrderedDict([('no', 'localhost')]) def send( self, request, stream=False, timeout=None, verify=True, cert=None, proxies=None ): """Sends PreparedRequest object. Returns Response object. :param request: The :class:`PreparedRequest ` being sent. :param stream: (optional) Whether to stream the request content. :param timeout: (optional) How long to wait for the server to send data before giving up, as a float, or a :ref:`(connect timeout, read timeout) ` tuple. :type timeout: float or tuple or urllib3 Timeout object :param verify: (optional) Either a boolean, in which case it controls whether we verify the server's TLS certificate, or a string, in which case it must be a path to a CA bundle to use :param cert: (optional) Any user-provided SSL certificate to be trusted. :param proxies: (optional) The proxies dictionary to apply to the request. :rtype: requests.Response """ try: conn = self.get_connection(request.url, proxies) except LocationValueError as e: raise InvalidURL(e, request=request) self.cert_verify(conn, request.url, verify, cert) url = self.request_url(request, proxies) self.add_headers( request, stream=stream, timeout=timeout, verify=verify, cert=cert, proxies=proxies, ) chunked = not (request.body is None or "Content-Length" in request.headers) if isinstance(timeout, tuple): try: connect, read = timeout timeout = TimeoutSauce(connect=connect, read=read) except ValueError: raise ValueError( f"Invalid timeout {timeout}. Pass a (connect, read) timeout tuple, " f"or a single float to set both timeouts to the same value." ) elif isinstance(timeout, TimeoutSauce): pass else: timeout = TimeoutSauce(connect=timeout, read=timeout) try: resp = conn.urlopen( method=request.method, url=url, body=request.body, headers=request.headers, redirect=False, assert_same_host=False, preload_content=False, decode_content=False, retries=self.max_retries, timeout=timeout, chunked=chunked, ) except (ProtocolError, OSError) as err: raise ConnectionError(err, request=request) except MaxRetryError as e: if isinstance(e.reason, ConnectTimeoutError): # TODO: Remove this in 3.0.0: see #2811 if not isinstance(e.reason, NewConnectionError): raise ConnectTimeout(e, request=request) if isinstance(e.reason, ResponseError): raise RetryError(e, request=request) if isinstance(e.reason, _ProxyError): raise ProxyError(e, request=request) if isinstance(e.reason, _SSLError): # This branch is for urllib3 v1.22 and later. raise SSLError(e, request=request) > raise ConnectionError(e, request=request) E requests.exceptions.ConnectionError: HTTPSConnectionPool(host='raw.githubusercontent.com', port=443): Max retries exceeded with url: /locustio/locust/master/examples/basic.py (Caused by NewConnectionError(': Failed to establish a new connection: [Errno -3] Temporary failure in name resolution')) /usr/lib/python3/dist-packages/requests/adapters.py:519: ConnectionError During handling of the above exception, another exception occurred: self = def test_locustfile_from_url(self): > locustfiles = parse_locustfile_option( args=[ "-f", "https://raw.githubusercontent.com/locustio/locust/master/examples/basic.py", ] ) locust/test/test_load_locustfile.py:216: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ locust/argument_parser.py:369: in parse_locustfile_option locustfile_as_list = [ locust/argument_parser.py:370: in download_locustfile_from_url(f) if is_url(f.strip()) else f.strip() for f in options.locustfile.split(",") _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ url = 'https://raw.githubusercontent.com/locustio/locust/master/examples/basic.py' def download_locustfile_from_url(url: str) -> str: try: response = requests.get(url) # Check if response is valid python code ast.parse(response.text) except requests.exceptions.RequestException as e: sys.stderr.write(f"Failed to get locustfile from: {url}. Exception: {e}") > sys.exit(1) E SystemExit: 1 locust/argument_parser.py:198: SystemExit ----------------------------- Captured stderr call ----------------------------- Failed to get locustfile from: https://raw.githubusercontent.com/locustio/locust/master/examples/basic.py. Exception: HTTPSConnectionPool(host='raw.githubusercontent.com', port=443): Max retries exceeded with url: /locustio/locust/master/examples/basic.py (Caused by NewConnectionError(': Failed to establish a new connection: [Errno -3] Temporary failure in name resolution')) _____________________ TestLoggingOptions.test_log_to_file ______________________ self = def test_log_to_file(self): with temporary_file( textwrap.dedent( """ import logging from locust import User, task, constant class MyUser(User): wait_time = constant(2) @task def my_task(self): print("running my_task") logging.info("custom log message") """ ) ) as file_path: with temporary_file("", suffix=".log") as log_file_path: try: > output = subprocess.check_output( [ "locust", "-f", file_path, "-u", "1", "-r", "1", "-t", "1", "--headless", "--logfile", log_file_path, ], stderr=subprocess.STDOUT, timeout=10, text=True, ) locust/test/test_log.py:158: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3/dist-packages/gevent/subprocess.py:405: in check_output with Popen(*popenargs, stdout=PIPE, **kwargs) as process: /usr/lib/python3/dist-packages/gevent/subprocess.py:808: in __init__ self._execute_child(args, executable, preexec_fn, close_fds, _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = args = ['locust', '-f', '/tmp/tmp4nysgi6r_locustfile.py', '-u', '1', '-r', ...] executable = 'locust', preexec_fn = None, close_fds = True, pass_fds = () cwd = None, env = None, universal_newlines = None, startupinfo = None creationflags = 0, shell = False, p2cread = -1, p2cwrite = -1, c2pread = 11 c2pwrite = 80, errread = -1, errwrite = 80, restore_signals = True, gid = None gids = None, uid = None, umask = -1, start_new_session = False process_group = None def _execute_child(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, universal_newlines, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, restore_signals, gid, gids, uid, umask, start_new_session, process_group): """Execute program (POSIX version)""" if isinstance(args, (str, bytes)): args = [args] elif isinstance(args, PathLike): if shell: raise TypeError('path-like args is not allowed when ' 'shell is true') args = [fsencode(args)] # os.PathLike -> [str] else: args = list(args) if shell: # On Android the default shell is at '/system/bin/sh'. unix_shell = ( '/system/bin/sh' if hasattr(sys, 'getandroidapilevel') else '/bin/sh' ) args = [unix_shell, "-c"] + args if executable: args[0] = executable if executable is None: executable = args[0] self._loop.install_sigchld() # For transferring possible exec failure from child to parent # The first char specifies the exception type: 0 means # OSError, 1 means some other error. errpipe_read, errpipe_write = self.pipe_cloexec() # errpipe_write must not be in the standard io 0, 1, or 2 fd range. low_fds_to_close = [] while errpipe_write < 3: low_fds_to_close.append(errpipe_write) errpipe_write = os.dup(errpipe_write) for low_fd in low_fds_to_close: os.close(low_fd) try: try: gc_was_enabled = gc.isenabled() # Disable gc to avoid bug where gc -> file_dealloc -> # write to stderr -> hang. http://bugs.python.org/issue1336 gc.disable() try: self.pid = fork_and_watch(self._on_child, self._loop, True, fork) except: if gc_was_enabled: gc.enable() raise if self.pid == 0: # Child # In various places on the child side of things, we catch OSError # and add attributes to it that detail where in the process we failed; # like all exceptions until we have exec'd, this exception is pickled # and sent to the parent to raise in the calling process. # The parent uses this to decide how to treat that exception, # adjusting certain information about it as needed. # # Python 3.11.8 --- yes, a minor patch release --- stopped # letting the 'filename' parameter get set in the resulting # exception for many cases. We're not quite interpreting this # the same way the stdlib is, I'm sure, but this makes the stdlib # tests pass. # XXX: Technically we're doing a lot of stuff here that # may not be safe to do before a exec(), depending on the OS. # CPython 3 goes to great lengths to precompute a lot # of this info before the fork and pass it all to C functions that # try hard not to call things like malloc(). (Of course, # CPython 2 pretty much did what we're doing.) try: # Close parent's pipe ends if p2cwrite != -1: os.close(p2cwrite) if c2pread != -1: os.close(c2pread) if errread != -1: os.close(errread) os.close(errpipe_read) # When duping fds, if there arises a situation # where one of the fds is either 0, 1 or 2, it # is possible that it is overwritten (#12607). if c2pwrite == 0: c2pwrite = os.dup(c2pwrite) _set_inheritable(c2pwrite, False) while errwrite in (0, 1): errwrite = os.dup(errwrite) _set_inheritable(errwrite, False) # Dup fds for child def _dup2(existing, desired): # dup2() removes the CLOEXEC flag but # we must do it ourselves if dup2() # would be a no-op (issue #10806). if existing == desired: self._set_cloexec_flag(existing, False) elif existing != -1: os.dup2(existing, desired) try: self._remove_nonblock_flag(desired) except OSError: # Ignore EBADF, it may not actually be # open yet. # Tested beginning in 3.7.0b3 test_subprocess.py pass _dup2(p2cread, 0) _dup2(c2pwrite, 1) _dup2(errwrite, 2) # Close pipe fds. Make sure we don't close the # same fd more than once, or standard fds. if not True: closed = set([None]) for fd in (p2cread, c2pwrite, errwrite): if fd not in closed and fd > 2: os.close(fd) closed.add(fd) # Python 3 (with a working set_inheritable): # We no longer manually close p2cread, # c2pwrite, and errwrite here as # _close_open_fds takes care when it is # not already non-inheritable. if cwd is not None: try: os.chdir(cwd) except OSError as e: e._failed_chdir = True raise # Python 3.9 if umask >= 0: os.umask(umask) # XXX: CPython does _Py_RestoreSignals here. # Then setsid() based on ??? try: if gids: os.setgroups(gids) if gid: os.setregid(gid, gid) if uid: os.setreuid(uid, uid) if process_group is not None: os.setpgid(0, process_group) except OSError as e: e._failed_chuser = True raise if preexec_fn: preexec_fn() # Close all other fds, if asked for. This must be done # after preexec_fn runs. if close_fds: fds_to_keep = set(pass_fds) fds_to_keep.add(errpipe_write) self._close_fds(fds_to_keep, errpipe_write) if restore_signals: # restore the documented signals back to sig_dfl; # not all will be defined on every platform for sig in 'SIGPIPE', 'SIGXFZ', 'SIGXFSZ': sig = getattr(signal, sig, None) if sig is not None: signal.signal(sig, signal.SIG_DFL) if start_new_session: os.setsid() try: if env is None: os.execvp(executable, args) else: # Python 3.6 started testing for # bytes values in the env; it also # started encoding strs using # fsencode and using a lower-level # API that takes a list of keys # and values. We don't have access # to that API, so we go the reverse direction. env = {os.fsdecode(k) if isinstance(k, bytes) else k: os.fsdecode(v) if isinstance(v, bytes) else v for k, v in env.items()} os.execvpe(executable, args, env) except OSError as e: e._failed_exec = True raise except: exc_type, exc_value, tb = sys.exc_info() # Save the traceback and attach it to the exception object exc_lines = traceback.format_exception(exc_type, exc_value, tb) exc_value.child_traceback = ''.join(exc_lines) os.write(errpipe_write, pickle.dumps(exc_value)) finally: # Make sure that the process exits no matter what. # The return code does not matter much as it won't be # reported to the application os._exit(1) # Parent self._child_created = True if gc_was_enabled: gc.enable() finally: # be sure the FD is closed no matter what os.close(errpipe_write) # self._devnull is not always defined. devnull_fd = getattr(self, '_devnull', None) if p2cread != -1 and p2cwrite != -1 and p2cread != devnull_fd: os.close(p2cread) if c2pwrite != -1 and c2pread != -1 and c2pwrite != devnull_fd: os.close(c2pwrite) if errwrite != -1 and errread != -1 and errwrite != devnull_fd: os.close(errwrite) if devnull_fd is not None: os.close(devnull_fd) # Prevent a double close of these fds from __init__ on error. self._closed_child_pipe_fds = True # Wait for exec to fail or succeed; possibly raising exception errpipe_read = FileObject(errpipe_read, 'rb') data = errpipe_read.read() finally: try: if hasattr(errpipe_read, 'close'): errpipe_read.close() else: os.close(errpipe_read) except OSError: # Especially on PyPy, we sometimes see the above # `os.close(errpipe_read)` raise an OSError. # It's not entirely clear why, but it happens in # InterprocessSignalTests.test_main sometimes, which must mean # we have some sort of race condition. pass finally: errpipe_read = -1 if data != b"": self.wait() child_exception = pickle.loads(data) for fd in (p2cwrite, c2pread, errread): if fd is not None and fd != -1: os.close(fd) if isinstance(child_exception, OSError): child_exception.filename = executable if hasattr(child_exception, '_failed_chdir'): child_exception.filename = cwd if getattr(child_exception, '_failed_chuser', False): child_exception.filename = None > raise child_exception E OSError: [Errno 8] Exec format error: 'locust' /usr/lib/python3/dist-packages/gevent/subprocess.py:1838: OSError ____________________ TestLoggingOptions.test_logging_output ____________________ self = def test_logging_output(self): with temporary_file( textwrap.dedent( """ import logging from locust import User, task, constant custom_logger = logging.getLogger("custom_logger") class MyUser(User): wait_time = constant(2) @task def my_task(self): print("running my_task") logging.info("custom log message") custom_logger.info("test") """ ) ) as file_path: > output = subprocess.check_output( [ "locust", "-f", file_path, "-u", "1", "-r", "1", "-t", "1", "--headless", ], stderr=subprocess.STDOUT, timeout=10, text=True, ) locust/test/test_log.py:58: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3/dist-packages/gevent/subprocess.py:405: in check_output with Popen(*popenargs, stdout=PIPE, **kwargs) as process: /usr/lib/python3/dist-packages/gevent/subprocess.py:808: in __init__ self._execute_child(args, executable, preexec_fn, close_fds, _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = args = ['locust', '-f', '/tmp/tmpoinr7exi_locustfile.py', '-u', '1', '-r', ...] executable = 'locust', preexec_fn = None, close_fds = True, pass_fds = () cwd = None, env = None, universal_newlines = None, startupinfo = None creationflags = 0, shell = False, p2cread = -1, p2cwrite = -1, c2pread = 11 c2pwrite = 80, errread = -1, errwrite = 80, restore_signals = True, gid = None gids = None, uid = None, umask = -1, start_new_session = False process_group = None def _execute_child(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, universal_newlines, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, restore_signals, gid, gids, uid, umask, start_new_session, process_group): """Execute program (POSIX version)""" if isinstance(args, (str, bytes)): args = [args] elif isinstance(args, PathLike): if shell: raise TypeError('path-like args is not allowed when ' 'shell is true') args = [fsencode(args)] # os.PathLike -> [str] else: args = list(args) if shell: # On Android the default shell is at '/system/bin/sh'. unix_shell = ( '/system/bin/sh' if hasattr(sys, 'getandroidapilevel') else '/bin/sh' ) args = [unix_shell, "-c"] + args if executable: args[0] = executable if executable is None: executable = args[0] self._loop.install_sigchld() # For transferring possible exec failure from child to parent # The first char specifies the exception type: 0 means # OSError, 1 means some other error. errpipe_read, errpipe_write = self.pipe_cloexec() # errpipe_write must not be in the standard io 0, 1, or 2 fd range. low_fds_to_close = [] while errpipe_write < 3: low_fds_to_close.append(errpipe_write) errpipe_write = os.dup(errpipe_write) for low_fd in low_fds_to_close: os.close(low_fd) try: try: gc_was_enabled = gc.isenabled() # Disable gc to avoid bug where gc -> file_dealloc -> # write to stderr -> hang. http://bugs.python.org/issue1336 gc.disable() try: self.pid = fork_and_watch(self._on_child, self._loop, True, fork) except: if gc_was_enabled: gc.enable() raise if self.pid == 0: # Child # In various places on the child side of things, we catch OSError # and add attributes to it that detail where in the process we failed; # like all exceptions until we have exec'd, this exception is pickled # and sent to the parent to raise in the calling process. # The parent uses this to decide how to treat that exception, # adjusting certain information about it as needed. # # Python 3.11.8 --- yes, a minor patch release --- stopped # letting the 'filename' parameter get set in the resulting # exception for many cases. We're not quite interpreting this # the same way the stdlib is, I'm sure, but this makes the stdlib # tests pass. # XXX: Technically we're doing a lot of stuff here that # may not be safe to do before a exec(), depending on the OS. # CPython 3 goes to great lengths to precompute a lot # of this info before the fork and pass it all to C functions that # try hard not to call things like malloc(). (Of course, # CPython 2 pretty much did what we're doing.) try: # Close parent's pipe ends if p2cwrite != -1: os.close(p2cwrite) if c2pread != -1: os.close(c2pread) if errread != -1: os.close(errread) os.close(errpipe_read) # When duping fds, if there arises a situation # where one of the fds is either 0, 1 or 2, it # is possible that it is overwritten (#12607). if c2pwrite == 0: c2pwrite = os.dup(c2pwrite) _set_inheritable(c2pwrite, False) while errwrite in (0, 1): errwrite = os.dup(errwrite) _set_inheritable(errwrite, False) # Dup fds for child def _dup2(existing, desired): # dup2() removes the CLOEXEC flag but # we must do it ourselves if dup2() # would be a no-op (issue #10806). if existing == desired: self._set_cloexec_flag(existing, False) elif existing != -1: os.dup2(existing, desired) try: self._remove_nonblock_flag(desired) except OSError: # Ignore EBADF, it may not actually be # open yet. # Tested beginning in 3.7.0b3 test_subprocess.py pass _dup2(p2cread, 0) _dup2(c2pwrite, 1) _dup2(errwrite, 2) # Close pipe fds. Make sure we don't close the # same fd more than once, or standard fds. if not True: closed = set([None]) for fd in (p2cread, c2pwrite, errwrite): if fd not in closed and fd > 2: os.close(fd) closed.add(fd) # Python 3 (with a working set_inheritable): # We no longer manually close p2cread, # c2pwrite, and errwrite here as # _close_open_fds takes care when it is # not already non-inheritable. if cwd is not None: try: os.chdir(cwd) except OSError as e: e._failed_chdir = True raise # Python 3.9 if umask >= 0: os.umask(umask) # XXX: CPython does _Py_RestoreSignals here. # Then setsid() based on ??? try: if gids: os.setgroups(gids) if gid: os.setregid(gid, gid) if uid: os.setreuid(uid, uid) if process_group is not None: os.setpgid(0, process_group) except OSError as e: e._failed_chuser = True raise if preexec_fn: preexec_fn() # Close all other fds, if asked for. This must be done # after preexec_fn runs. if close_fds: fds_to_keep = set(pass_fds) fds_to_keep.add(errpipe_write) self._close_fds(fds_to_keep, errpipe_write) if restore_signals: # restore the documented signals back to sig_dfl; # not all will be defined on every platform for sig in 'SIGPIPE', 'SIGXFZ', 'SIGXFSZ': sig = getattr(signal, sig, None) if sig is not None: signal.signal(sig, signal.SIG_DFL) if start_new_session: os.setsid() try: if env is None: os.execvp(executable, args) else: # Python 3.6 started testing for # bytes values in the env; it also # started encoding strs using # fsencode and using a lower-level # API that takes a list of keys # and values. We don't have access # to that API, so we go the reverse direction. env = {os.fsdecode(k) if isinstance(k, bytes) else k: os.fsdecode(v) if isinstance(v, bytes) else v for k, v in env.items()} os.execvpe(executable, args, env) except OSError as e: e._failed_exec = True raise except: exc_type, exc_value, tb = sys.exc_info() # Save the traceback and attach it to the exception object exc_lines = traceback.format_exception(exc_type, exc_value, tb) exc_value.child_traceback = ''.join(exc_lines) os.write(errpipe_write, pickle.dumps(exc_value)) finally: # Make sure that the process exits no matter what. # The return code does not matter much as it won't be # reported to the application os._exit(1) # Parent self._child_created = True if gc_was_enabled: gc.enable() finally: # be sure the FD is closed no matter what os.close(errpipe_write) # self._devnull is not always defined. devnull_fd = getattr(self, '_devnull', None) if p2cread != -1 and p2cwrite != -1 and p2cread != devnull_fd: os.close(p2cread) if c2pwrite != -1 and c2pread != -1 and c2pwrite != devnull_fd: os.close(c2pwrite) if errwrite != -1 and errread != -1 and errwrite != devnull_fd: os.close(errwrite) if devnull_fd is not None: os.close(devnull_fd) # Prevent a double close of these fds from __init__ on error. self._closed_child_pipe_fds = True # Wait for exec to fail or succeed; possibly raising exception errpipe_read = FileObject(errpipe_read, 'rb') data = errpipe_read.read() finally: try: if hasattr(errpipe_read, 'close'): errpipe_read.close() else: os.close(errpipe_read) except OSError: # Especially on PyPy, we sometimes see the above # `os.close(errpipe_read)` raise an OSError. # It's not entirely clear why, but it happens in # InterprocessSignalTests.test_main sometimes, which must mean # we have some sort of race condition. pass finally: errpipe_read = -1 if data != b"": self.wait() child_exception = pickle.loads(data) for fd in (p2cwrite, c2pread, errread): if fd is not None and fd != -1: os.close(fd) if isinstance(child_exception, OSError): child_exception.filename = executable if hasattr(child_exception, '_failed_chdir'): child_exception.filename = cwd if getattr(child_exception, '_failed_chuser', False): child_exception.filename = None > raise child_exception E OSError: [Errno 8] Exec format error: 'locust' /usr/lib/python3/dist-packages/gevent/subprocess.py:1838: OSError _____________________ TestLoggingOptions.test_skip_logging _____________________ self = def test_skip_logging(self): with temporary_file( textwrap.dedent( """ from locust import User, task, constant class MyUser(User): wait_time = constant(2) @task def my_task(self): print("running my_task") """ ) ) as file_path: > output = subprocess.check_output( [ "locust", "-f", file_path, "-u", "1", "-r", "1", "-t", "1", "--headless", "--skip-log-setup", ], stderr=subprocess.STDOUT, timeout=10, text=True, ) locust/test/test_log.py:117: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3/dist-packages/gevent/subprocess.py:405: in check_output with Popen(*popenargs, stdout=PIPE, **kwargs) as process: /usr/lib/python3/dist-packages/gevent/subprocess.py:808: in __init__ self._execute_child(args, executable, preexec_fn, close_fds, _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = args = ['locust', '-f', '/tmp/tmpvvtdtnmk_locustfile.py', '-u', '1', '-r', ...] executable = 'locust', preexec_fn = None, close_fds = True, pass_fds = () cwd = None, env = None, universal_newlines = None, startupinfo = None creationflags = 0, shell = False, p2cread = -1, p2cwrite = -1, c2pread = 11 c2pwrite = 80, errread = -1, errwrite = 80, restore_signals = True, gid = None gids = None, uid = None, umask = -1, start_new_session = False process_group = None def _execute_child(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, universal_newlines, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, restore_signals, gid, gids, uid, umask, start_new_session, process_group): """Execute program (POSIX version)""" if isinstance(args, (str, bytes)): args = [args] elif isinstance(args, PathLike): if shell: raise TypeError('path-like args is not allowed when ' 'shell is true') args = [fsencode(args)] # os.PathLike -> [str] else: args = list(args) if shell: # On Android the default shell is at '/system/bin/sh'. unix_shell = ( '/system/bin/sh' if hasattr(sys, 'getandroidapilevel') else '/bin/sh' ) args = [unix_shell, "-c"] + args if executable: args[0] = executable if executable is None: executable = args[0] self._loop.install_sigchld() # For transferring possible exec failure from child to parent # The first char specifies the exception type: 0 means # OSError, 1 means some other error. errpipe_read, errpipe_write = self.pipe_cloexec() # errpipe_write must not be in the standard io 0, 1, or 2 fd range. low_fds_to_close = [] while errpipe_write < 3: low_fds_to_close.append(errpipe_write) errpipe_write = os.dup(errpipe_write) for low_fd in low_fds_to_close: os.close(low_fd) try: try: gc_was_enabled = gc.isenabled() # Disable gc to avoid bug where gc -> file_dealloc -> # write to stderr -> hang. http://bugs.python.org/issue1336 gc.disable() try: self.pid = fork_and_watch(self._on_child, self._loop, True, fork) except: if gc_was_enabled: gc.enable() raise if self.pid == 0: # Child # In various places on the child side of things, we catch OSError # and add attributes to it that detail where in the process we failed; # like all exceptions until we have exec'd, this exception is pickled # and sent to the parent to raise in the calling process. # The parent uses this to decide how to treat that exception, # adjusting certain information about it as needed. # # Python 3.11.8 --- yes, a minor patch release --- stopped # letting the 'filename' parameter get set in the resulting # exception for many cases. We're not quite interpreting this # the same way the stdlib is, I'm sure, but this makes the stdlib # tests pass. # XXX: Technically we're doing a lot of stuff here that # may not be safe to do before a exec(), depending on the OS. # CPython 3 goes to great lengths to precompute a lot # of this info before the fork and pass it all to C functions that # try hard not to call things like malloc(). (Of course, # CPython 2 pretty much did what we're doing.) try: # Close parent's pipe ends if p2cwrite != -1: os.close(p2cwrite) if c2pread != -1: os.close(c2pread) if errread != -1: os.close(errread) os.close(errpipe_read) # When duping fds, if there arises a situation # where one of the fds is either 0, 1 or 2, it # is possible that it is overwritten (#12607). if c2pwrite == 0: c2pwrite = os.dup(c2pwrite) _set_inheritable(c2pwrite, False) while errwrite in (0, 1): errwrite = os.dup(errwrite) _set_inheritable(errwrite, False) # Dup fds for child def _dup2(existing, desired): # dup2() removes the CLOEXEC flag but # we must do it ourselves if dup2() # would be a no-op (issue #10806). if existing == desired: self._set_cloexec_flag(existing, False) elif existing != -1: os.dup2(existing, desired) try: self._remove_nonblock_flag(desired) except OSError: # Ignore EBADF, it may not actually be # open yet. # Tested beginning in 3.7.0b3 test_subprocess.py pass _dup2(p2cread, 0) _dup2(c2pwrite, 1) _dup2(errwrite, 2) # Close pipe fds. Make sure we don't close the # same fd more than once, or standard fds. if not True: closed = set([None]) for fd in (p2cread, c2pwrite, errwrite): if fd not in closed and fd > 2: os.close(fd) closed.add(fd) # Python 3 (with a working set_inheritable): # We no longer manually close p2cread, # c2pwrite, and errwrite here as # _close_open_fds takes care when it is # not already non-inheritable. if cwd is not None: try: os.chdir(cwd) except OSError as e: e._failed_chdir = True raise # Python 3.9 if umask >= 0: os.umask(umask) # XXX: CPython does _Py_RestoreSignals here. # Then setsid() based on ??? try: if gids: os.setgroups(gids) if gid: os.setregid(gid, gid) if uid: os.setreuid(uid, uid) if process_group is not None: os.setpgid(0, process_group) except OSError as e: e._failed_chuser = True raise if preexec_fn: preexec_fn() # Close all other fds, if asked for. This must be done # after preexec_fn runs. if close_fds: fds_to_keep = set(pass_fds) fds_to_keep.add(errpipe_write) self._close_fds(fds_to_keep, errpipe_write) if restore_signals: # restore the documented signals back to sig_dfl; # not all will be defined on every platform for sig in 'SIGPIPE', 'SIGXFZ', 'SIGXFSZ': sig = getattr(signal, sig, None) if sig is not None: signal.signal(sig, signal.SIG_DFL) if start_new_session: os.setsid() try: if env is None: os.execvp(executable, args) else: # Python 3.6 started testing for # bytes values in the env; it also # started encoding strs using # fsencode and using a lower-level # API that takes a list of keys # and values. We don't have access # to that API, so we go the reverse direction. env = {os.fsdecode(k) if isinstance(k, bytes) else k: os.fsdecode(v) if isinstance(v, bytes) else v for k, v in env.items()} os.execvpe(executable, args, env) except OSError as e: e._failed_exec = True raise except: exc_type, exc_value, tb = sys.exc_info() # Save the traceback and attach it to the exception object exc_lines = traceback.format_exception(exc_type, exc_value, tb) exc_value.child_traceback = ''.join(exc_lines) os.write(errpipe_write, pickle.dumps(exc_value)) finally: # Make sure that the process exits no matter what. # The return code does not matter much as it won't be # reported to the application os._exit(1) # Parent self._child_created = True if gc_was_enabled: gc.enable() finally: # be sure the FD is closed no matter what os.close(errpipe_write) # self._devnull is not always defined. devnull_fd = getattr(self, '_devnull', None) if p2cread != -1 and p2cwrite != -1 and p2cread != devnull_fd: os.close(p2cread) if c2pwrite != -1 and c2pread != -1 and c2pwrite != devnull_fd: os.close(c2pwrite) if errwrite != -1 and errread != -1 and errwrite != devnull_fd: os.close(errwrite) if devnull_fd is not None: os.close(devnull_fd) # Prevent a double close of these fds from __init__ on error. self._closed_child_pipe_fds = True # Wait for exec to fail or succeed; possibly raising exception errpipe_read = FileObject(errpipe_read, 'rb') data = errpipe_read.read() finally: try: if hasattr(errpipe_read, 'close'): errpipe_read.close() else: os.close(errpipe_read) except OSError: # Especially on PyPy, we sometimes see the above # `os.close(errpipe_read)` raise an OSError. # It's not entirely clear why, but it happens in # InterprocessSignalTests.test_main sometimes, which must mean # we have some sort of race condition. pass finally: errpipe_read = -1 if data != b"": self.wait() child_exception = pickle.loads(data) for fd in (p2cwrite, c2pread, errread): if fd is not None and fd != -1: os.close(fd) if isinstance(child_exception, OSError): child_exception.filename = executable if hasattr(child_exception, '_failed_chdir'): child_exception.filename = cwd if getattr(child_exception, '_failed_chuser', False): child_exception.filename = None > raise child_exception E OSError: [Errno 8] Exec format error: 'locust' /usr/lib/python3/dist-packages/gevent/subprocess.py:1838: OSError _________________ TestLoggingOptions.test_user_broken_on_start _________________ self = def test_user_broken_on_start(self): with temporary_file( textwrap.dedent( """ from locust import HttpUser, task class TestUser(HttpUser): host = "invalidhost" def on_start(self): self.client.get("/") """ ) ) as file_path: > output = subprocess.check_output( [ "locust", "-f", file_path, "-t", "1", "--headless", ], stderr=subprocess.STDOUT, timeout=10, text=True, ) locust/test/test_log.py:223: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3/dist-packages/gevent/subprocess.py:405: in check_output with Popen(*popenargs, stdout=PIPE, **kwargs) as process: /usr/lib/python3/dist-packages/gevent/subprocess.py:808: in __init__ self._execute_child(args, executable, preexec_fn, close_fds, _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = args = ['locust', '-f', '/tmp/tmppbj8r75__locustfile.py', '-t', '1', '--headless'] executable = 'locust', preexec_fn = None, close_fds = True, pass_fds = () cwd = None, env = None, universal_newlines = None, startupinfo = None creationflags = 0, shell = False, p2cread = -1, p2cwrite = -1, c2pread = 11 c2pwrite = 80, errread = -1, errwrite = 80, restore_signals = True, gid = None gids = None, uid = None, umask = -1, start_new_session = False process_group = None def _execute_child(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, universal_newlines, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, restore_signals, gid, gids, uid, umask, start_new_session, process_group): """Execute program (POSIX version)""" if isinstance(args, (str, bytes)): args = [args] elif isinstance(args, PathLike): if shell: raise TypeError('path-like args is not allowed when ' 'shell is true') args = [fsencode(args)] # os.PathLike -> [str] else: args = list(args) if shell: # On Android the default shell is at '/system/bin/sh'. unix_shell = ( '/system/bin/sh' if hasattr(sys, 'getandroidapilevel') else '/bin/sh' ) args = [unix_shell, "-c"] + args if executable: args[0] = executable if executable is None: executable = args[0] self._loop.install_sigchld() # For transferring possible exec failure from child to parent # The first char specifies the exception type: 0 means # OSError, 1 means some other error. errpipe_read, errpipe_write = self.pipe_cloexec() # errpipe_write must not be in the standard io 0, 1, or 2 fd range. low_fds_to_close = [] while errpipe_write < 3: low_fds_to_close.append(errpipe_write) errpipe_write = os.dup(errpipe_write) for low_fd in low_fds_to_close: os.close(low_fd) try: try: gc_was_enabled = gc.isenabled() # Disable gc to avoid bug where gc -> file_dealloc -> # write to stderr -> hang. http://bugs.python.org/issue1336 gc.disable() try: self.pid = fork_and_watch(self._on_child, self._loop, True, fork) except: if gc_was_enabled: gc.enable() raise if self.pid == 0: # Child # In various places on the child side of things, we catch OSError # and add attributes to it that detail where in the process we failed; # like all exceptions until we have exec'd, this exception is pickled # and sent to the parent to raise in the calling process. # The parent uses this to decide how to treat that exception, # adjusting certain information about it as needed. # # Python 3.11.8 --- yes, a minor patch release --- stopped # letting the 'filename' parameter get set in the resulting # exception for many cases. We're not quite interpreting this # the same way the stdlib is, I'm sure, but this makes the stdlib # tests pass. # XXX: Technically we're doing a lot of stuff here that # may not be safe to do before a exec(), depending on the OS. # CPython 3 goes to great lengths to precompute a lot # of this info before the fork and pass it all to C functions that # try hard not to call things like malloc(). (Of course, # CPython 2 pretty much did what we're doing.) try: # Close parent's pipe ends if p2cwrite != -1: os.close(p2cwrite) if c2pread != -1: os.close(c2pread) if errread != -1: os.close(errread) os.close(errpipe_read) # When duping fds, if there arises a situation # where one of the fds is either 0, 1 or 2, it # is possible that it is overwritten (#12607). if c2pwrite == 0: c2pwrite = os.dup(c2pwrite) _set_inheritable(c2pwrite, False) while errwrite in (0, 1): errwrite = os.dup(errwrite) _set_inheritable(errwrite, False) # Dup fds for child def _dup2(existing, desired): # dup2() removes the CLOEXEC flag but # we must do it ourselves if dup2() # would be a no-op (issue #10806). if existing == desired: self._set_cloexec_flag(existing, False) elif existing != -1: os.dup2(existing, desired) try: self._remove_nonblock_flag(desired) except OSError: # Ignore EBADF, it may not actually be # open yet. # Tested beginning in 3.7.0b3 test_subprocess.py pass _dup2(p2cread, 0) _dup2(c2pwrite, 1) _dup2(errwrite, 2) # Close pipe fds. Make sure we don't close the # same fd more than once, or standard fds. if not True: closed = set([None]) for fd in (p2cread, c2pwrite, errwrite): if fd not in closed and fd > 2: os.close(fd) closed.add(fd) # Python 3 (with a working set_inheritable): # We no longer manually close p2cread, # c2pwrite, and errwrite here as # _close_open_fds takes care when it is # not already non-inheritable. if cwd is not None: try: os.chdir(cwd) except OSError as e: e._failed_chdir = True raise # Python 3.9 if umask >= 0: os.umask(umask) # XXX: CPython does _Py_RestoreSignals here. # Then setsid() based on ??? try: if gids: os.setgroups(gids) if gid: os.setregid(gid, gid) if uid: os.setreuid(uid, uid) if process_group is not None: os.setpgid(0, process_group) except OSError as e: e._failed_chuser = True raise if preexec_fn: preexec_fn() # Close all other fds, if asked for. This must be done # after preexec_fn runs. if close_fds: fds_to_keep = set(pass_fds) fds_to_keep.add(errpipe_write) self._close_fds(fds_to_keep, errpipe_write) if restore_signals: # restore the documented signals back to sig_dfl; # not all will be defined on every platform for sig in 'SIGPIPE', 'SIGXFZ', 'SIGXFSZ': sig = getattr(signal, sig, None) if sig is not None: signal.signal(sig, signal.SIG_DFL) if start_new_session: os.setsid() try: if env is None: os.execvp(executable, args) else: # Python 3.6 started testing for # bytes values in the env; it also # started encoding strs using # fsencode and using a lower-level # API that takes a list of keys # and values. We don't have access # to that API, so we go the reverse direction. env = {os.fsdecode(k) if isinstance(k, bytes) else k: os.fsdecode(v) if isinstance(v, bytes) else v for k, v in env.items()} os.execvpe(executable, args, env) except OSError as e: e._failed_exec = True raise except: exc_type, exc_value, tb = sys.exc_info() # Save the traceback and attach it to the exception object exc_lines = traceback.format_exception(exc_type, exc_value, tb) exc_value.child_traceback = ''.join(exc_lines) os.write(errpipe_write, pickle.dumps(exc_value)) finally: # Make sure that the process exits no matter what. # The return code does not matter much as it won't be # reported to the application os._exit(1) # Parent self._child_created = True if gc_was_enabled: gc.enable() finally: # be sure the FD is closed no matter what os.close(errpipe_write) # self._devnull is not always defined. devnull_fd = getattr(self, '_devnull', None) if p2cread != -1 and p2cwrite != -1 and p2cread != devnull_fd: os.close(p2cread) if c2pwrite != -1 and c2pread != -1 and c2pwrite != devnull_fd: os.close(c2pwrite) if errwrite != -1 and errread != -1 and errwrite != devnull_fd: os.close(errwrite) if devnull_fd is not None: os.close(devnull_fd) # Prevent a double close of these fds from __init__ on error. self._closed_child_pipe_fds = True # Wait for exec to fail or succeed; possibly raising exception errpipe_read = FileObject(errpipe_read, 'rb') data = errpipe_read.read() finally: try: if hasattr(errpipe_read, 'close'): errpipe_read.close() else: os.close(errpipe_read) except OSError: # Especially on PyPy, we sometimes see the above # `os.close(errpipe_read)` raise an OSError. # It's not entirely clear why, but it happens in # InterprocessSignalTests.test_main sometimes, which must mean # we have some sort of race condition. pass finally: errpipe_read = -1 if data != b"": self.wait() child_exception = pickle.loads(data) for fd in (p2cwrite, c2pread, errread): if fd is not None and fd != -1: os.close(fd) if isinstance(child_exception, OSError): child_exception.filename = executable if hasattr(child_exception, '_failed_chdir'): child_exception.filename = cwd if getattr(child_exception, '_failed_chuser', False): child_exception.filename = None > raise child_exception E OSError: [Errno 8] Exec format error: 'locust' /usr/lib/python3/dist-packages/gevent/subprocess.py:1838: OSError __ StandaloneIntegrationTests.test_autostart_multiple_locustfiles_with_shape ___ self = def test_autostart_multiple_locustfiles_with_shape(self): port = get_free_tcp_port() content = textwrap.dedent( """ from locust import User, task, between class TestUser2(User): wait_time = between(2, 4) @task def my_task(self): print("running my_task() again") """ ) with mock_locustfile(content=content) as mocked1: with temporary_file( content=textwrap.dedent( """ from locust import User, task, between, LoadTestShape class LoadTestShape(LoadTestShape): def tick(self): run_time = self.get_run_time() if run_time < 2: return (10, 1) return None class TestUser(User): wait_time = between(2, 4) @task def my_task(self): print("running my_task()") """ ) ) as mocked2: > proc = subprocess.Popen( [ "locust", "-f", f"{mocked1.file_path},{mocked2}", "--legacy-ui", "--web-port", str(port), "--autostart", "--autoquit", "3", ], stdout=PIPE, stderr=PIPE, text=True, ) locust/test/test_main.py:794: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3/dist-packages/gevent/subprocess.py:808: in __init__ self._execute_child(args, executable, preexec_fn, close_fds, _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = args = ['locust', '-f', '/build/reproducible-path/locust-2.24.0/locust/test/mock_locustfile_1715256371_6013396_51542.py,/tmp/tmppglq72n4_locustfile.py', '--legacy-ui', '--web-port', '39551', ...] executable = 'locust', preexec_fn = None, close_fds = True, pass_fds = () cwd = None, env = None, universal_newlines = None, startupinfo = None creationflags = 0, shell = False, p2cread = -1, p2cwrite = -1, c2pread = 11 c2pwrite = 80, errread = 81, errwrite = 82, restore_signals = True, gid = None gids = None, uid = None, umask = -1, start_new_session = False process_group = None def _execute_child(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, universal_newlines, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, restore_signals, gid, gids, uid, umask, start_new_session, process_group): """Execute program (POSIX version)""" if isinstance(args, (str, bytes)): args = [args] elif isinstance(args, PathLike): if shell: raise TypeError('path-like args is not allowed when ' 'shell is true') args = [fsencode(args)] # os.PathLike -> [str] else: args = list(args) if shell: # On Android the default shell is at '/system/bin/sh'. unix_shell = ( '/system/bin/sh' if hasattr(sys, 'getandroidapilevel') else '/bin/sh' ) args = [unix_shell, "-c"] + args if executable: args[0] = executable if executable is None: executable = args[0] self._loop.install_sigchld() # For transferring possible exec failure from child to parent # The first char specifies the exception type: 0 means # OSError, 1 means some other error. errpipe_read, errpipe_write = self.pipe_cloexec() # errpipe_write must not be in the standard io 0, 1, or 2 fd range. low_fds_to_close = [] while errpipe_write < 3: low_fds_to_close.append(errpipe_write) errpipe_write = os.dup(errpipe_write) for low_fd in low_fds_to_close: os.close(low_fd) try: try: gc_was_enabled = gc.isenabled() # Disable gc to avoid bug where gc -> file_dealloc -> # write to stderr -> hang. http://bugs.python.org/issue1336 gc.disable() try: self.pid = fork_and_watch(self._on_child, self._loop, True, fork) except: if gc_was_enabled: gc.enable() raise if self.pid == 0: # Child # In various places on the child side of things, we catch OSError # and add attributes to it that detail where in the process we failed; # like all exceptions until we have exec'd, this exception is pickled # and sent to the parent to raise in the calling process. # The parent uses this to decide how to treat that exception, # adjusting certain information about it as needed. # # Python 3.11.8 --- yes, a minor patch release --- stopped # letting the 'filename' parameter get set in the resulting # exception for many cases. We're not quite interpreting this # the same way the stdlib is, I'm sure, but this makes the stdlib # tests pass. # XXX: Technically we're doing a lot of stuff here that # may not be safe to do before a exec(), depending on the OS. # CPython 3 goes to great lengths to precompute a lot # of this info before the fork and pass it all to C functions that # try hard not to call things like malloc(). (Of course, # CPython 2 pretty much did what we're doing.) try: # Close parent's pipe ends if p2cwrite != -1: os.close(p2cwrite) if c2pread != -1: os.close(c2pread) if errread != -1: os.close(errread) os.close(errpipe_read) # When duping fds, if there arises a situation # where one of the fds is either 0, 1 or 2, it # is possible that it is overwritten (#12607). if c2pwrite == 0: c2pwrite = os.dup(c2pwrite) _set_inheritable(c2pwrite, False) while errwrite in (0, 1): errwrite = os.dup(errwrite) _set_inheritable(errwrite, False) # Dup fds for child def _dup2(existing, desired): # dup2() removes the CLOEXEC flag but # we must do it ourselves if dup2() # would be a no-op (issue #10806). if existing == desired: self._set_cloexec_flag(existing, False) elif existing != -1: os.dup2(existing, desired) try: self._remove_nonblock_flag(desired) except OSError: # Ignore EBADF, it may not actually be # open yet. # Tested beginning in 3.7.0b3 test_subprocess.py pass _dup2(p2cread, 0) _dup2(c2pwrite, 1) _dup2(errwrite, 2) # Close pipe fds. Make sure we don't close the # same fd more than once, or standard fds. if not True: closed = set([None]) for fd in (p2cread, c2pwrite, errwrite): if fd not in closed and fd > 2: os.close(fd) closed.add(fd) # Python 3 (with a working set_inheritable): # We no longer manually close p2cread, # c2pwrite, and errwrite here as # _close_open_fds takes care when it is # not already non-inheritable. if cwd is not None: try: os.chdir(cwd) except OSError as e: e._failed_chdir = True raise # Python 3.9 if umask >= 0: os.umask(umask) # XXX: CPython does _Py_RestoreSignals here. # Then setsid() based on ??? try: if gids: os.setgroups(gids) if gid: os.setregid(gid, gid) if uid: os.setreuid(uid, uid) if process_group is not None: os.setpgid(0, process_group) except OSError as e: e._failed_chuser = True raise if preexec_fn: preexec_fn() # Close all other fds, if asked for. This must be done # after preexec_fn runs. if close_fds: fds_to_keep = set(pass_fds) fds_to_keep.add(errpipe_write) self._close_fds(fds_to_keep, errpipe_write) if restore_signals: # restore the documented signals back to sig_dfl; # not all will be defined on every platform for sig in 'SIGPIPE', 'SIGXFZ', 'SIGXFSZ': sig = getattr(signal, sig, None) if sig is not None: signal.signal(sig, signal.SIG_DFL) if start_new_session: os.setsid() try: if env is None: os.execvp(executable, args) else: # Python 3.6 started testing for # bytes values in the env; it also # started encoding strs using # fsencode and using a lower-level # API that takes a list of keys # and values. We don't have access # to that API, so we go the reverse direction. env = {os.fsdecode(k) if isinstance(k, bytes) else k: os.fsdecode(v) if isinstance(v, bytes) else v for k, v in env.items()} os.execvpe(executable, args, env) except OSError as e: e._failed_exec = True raise except: exc_type, exc_value, tb = sys.exc_info() # Save the traceback and attach it to the exception object exc_lines = traceback.format_exception(exc_type, exc_value, tb) exc_value.child_traceback = ''.join(exc_lines) os.write(errpipe_write, pickle.dumps(exc_value)) finally: # Make sure that the process exits no matter what. # The return code does not matter much as it won't be # reported to the application os._exit(1) # Parent self._child_created = True if gc_was_enabled: gc.enable() finally: # be sure the FD is closed no matter what os.close(errpipe_write) # self._devnull is not always defined. devnull_fd = getattr(self, '_devnull', None) if p2cread != -1 and p2cwrite != -1 and p2cread != devnull_fd: os.close(p2cread) if c2pwrite != -1 and c2pread != -1 and c2pwrite != devnull_fd: os.close(c2pwrite) if errwrite != -1 and errread != -1 and errwrite != devnull_fd: os.close(errwrite) if devnull_fd is not None: os.close(devnull_fd) # Prevent a double close of these fds from __init__ on error. self._closed_child_pipe_fds = True # Wait for exec to fail or succeed; possibly raising exception errpipe_read = FileObject(errpipe_read, 'rb') data = errpipe_read.read() finally: try: if hasattr(errpipe_read, 'close'): errpipe_read.close() else: os.close(errpipe_read) except OSError: # Especially on PyPy, we sometimes see the above # `os.close(errpipe_read)` raise an OSError. # It's not entirely clear why, but it happens in # InterprocessSignalTests.test_main sometimes, which must mean # we have some sort of race condition. pass finally: errpipe_read = -1 if data != b"": self.wait() child_exception = pickle.loads(data) for fd in (p2cwrite, c2pread, errread): if fd is not None and fd != -1: os.close(fd) if isinstance(child_exception, OSError): child_exception.filename = executable if hasattr(child_exception, '_failed_chdir'): child_exception.filename = cwd if getattr(child_exception, '_failed_chuser', False): child_exception.filename = None > raise child_exception E OSError: [Errno 8] Exec format error: 'locust' /usr/lib/python3/dist-packages/gevent/subprocess.py:1838: OSError ____________ StandaloneIntegrationTests.test_autostart_w_load_shape ____________ self = def test_autostart_w_load_shape(self): port = get_free_tcp_port() with mock_locustfile( content=MOCK_LOCUSTFILE_CONTENT + textwrap.dedent( """ from locust import LoadTestShape class LoadTestShape(LoadTestShape): def tick(self): run_time = self.get_run_time() if run_time < 2: return (10, 1) return None """ ) ) as mocked: > proc = subprocess.Popen( [ "locust", "-f", mocked.file_path, "--legacy-ui", "--web-port", str(port), "--autostart", "--autoquit", "3", ], stdout=PIPE, stderr=PIPE, text=True, ) locust/test/test_main.py:727: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3/dist-packages/gevent/subprocess.py:808: in __init__ self._execute_child(args, executable, preexec_fn, close_fds, _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = args = ['locust', '-f', '/build/reproducible-path/locust-2.24.0/locust/test/mock_locustfile_1715256371_8051176_66094.py', '--legacy-ui', '--web-port', '60105', ...] executable = 'locust', preexec_fn = None, close_fds = True, pass_fds = () cwd = None, env = None, universal_newlines = None, startupinfo = None creationflags = 0, shell = False, p2cread = -1, p2cwrite = -1, c2pread = 11 c2pwrite = 80, errread = 81, errwrite = 82, restore_signals = True, gid = None gids = None, uid = None, umask = -1, start_new_session = False process_group = None def _execute_child(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, universal_newlines, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, restore_signals, gid, gids, uid, umask, start_new_session, process_group): """Execute program (POSIX version)""" if isinstance(args, (str, bytes)): args = [args] elif isinstance(args, PathLike): if shell: raise TypeError('path-like args is not allowed when ' 'shell is true') args = [fsencode(args)] # os.PathLike -> [str] else: args = list(args) if shell: # On Android the default shell is at '/system/bin/sh'. unix_shell = ( '/system/bin/sh' if hasattr(sys, 'getandroidapilevel') else '/bin/sh' ) args = [unix_shell, "-c"] + args if executable: args[0] = executable if executable is None: executable = args[0] self._loop.install_sigchld() # For transferring possible exec failure from child to parent # The first char specifies the exception type: 0 means # OSError, 1 means some other error. errpipe_read, errpipe_write = self.pipe_cloexec() # errpipe_write must not be in the standard io 0, 1, or 2 fd range. low_fds_to_close = [] while errpipe_write < 3: low_fds_to_close.append(errpipe_write) errpipe_write = os.dup(errpipe_write) for low_fd in low_fds_to_close: os.close(low_fd) try: try: gc_was_enabled = gc.isenabled() # Disable gc to avoid bug where gc -> file_dealloc -> # write to stderr -> hang. http://bugs.python.org/issue1336 gc.disable() try: self.pid = fork_and_watch(self._on_child, self._loop, True, fork) except: if gc_was_enabled: gc.enable() raise if self.pid == 0: # Child # In various places on the child side of things, we catch OSError # and add attributes to it that detail where in the process we failed; # like all exceptions until we have exec'd, this exception is pickled # and sent to the parent to raise in the calling process. # The parent uses this to decide how to treat that exception, # adjusting certain information about it as needed. # # Python 3.11.8 --- yes, a minor patch release --- stopped # letting the 'filename' parameter get set in the resulting # exception for many cases. We're not quite interpreting this # the same way the stdlib is, I'm sure, but this makes the stdlib # tests pass. # XXX: Technically we're doing a lot of stuff here that # may not be safe to do before a exec(), depending on the OS. # CPython 3 goes to great lengths to precompute a lot # of this info before the fork and pass it all to C functions that # try hard not to call things like malloc(). (Of course, # CPython 2 pretty much did what we're doing.) try: # Close parent's pipe ends if p2cwrite != -1: os.close(p2cwrite) if c2pread != -1: os.close(c2pread) if errread != -1: os.close(errread) os.close(errpipe_read) # When duping fds, if there arises a situation # where one of the fds is either 0, 1 or 2, it # is possible that it is overwritten (#12607). if c2pwrite == 0: c2pwrite = os.dup(c2pwrite) _set_inheritable(c2pwrite, False) while errwrite in (0, 1): errwrite = os.dup(errwrite) _set_inheritable(errwrite, False) # Dup fds for child def _dup2(existing, desired): # dup2() removes the CLOEXEC flag but # we must do it ourselves if dup2() # would be a no-op (issue #10806). if existing == desired: self._set_cloexec_flag(existing, False) elif existing != -1: os.dup2(existing, desired) try: self._remove_nonblock_flag(desired) except OSError: # Ignore EBADF, it may not actually be # open yet. # Tested beginning in 3.7.0b3 test_subprocess.py pass _dup2(p2cread, 0) _dup2(c2pwrite, 1) _dup2(errwrite, 2) # Close pipe fds. Make sure we don't close the # same fd more than once, or standard fds. if not True: closed = set([None]) for fd in (p2cread, c2pwrite, errwrite): if fd not in closed and fd > 2: os.close(fd) closed.add(fd) # Python 3 (with a working set_inheritable): # We no longer manually close p2cread, # c2pwrite, and errwrite here as # _close_open_fds takes care when it is # not already non-inheritable. if cwd is not None: try: os.chdir(cwd) except OSError as e: e._failed_chdir = True raise # Python 3.9 if umask >= 0: os.umask(umask) # XXX: CPython does _Py_RestoreSignals here. # Then setsid() based on ??? try: if gids: os.setgroups(gids) if gid: os.setregid(gid, gid) if uid: os.setreuid(uid, uid) if process_group is not None: os.setpgid(0, process_group) except OSError as e: e._failed_chuser = True raise if preexec_fn: preexec_fn() # Close all other fds, if asked for. This must be done # after preexec_fn runs. if close_fds: fds_to_keep = set(pass_fds) fds_to_keep.add(errpipe_write) self._close_fds(fds_to_keep, errpipe_write) if restore_signals: # restore the documented signals back to sig_dfl; # not all will be defined on every platform for sig in 'SIGPIPE', 'SIGXFZ', 'SIGXFSZ': sig = getattr(signal, sig, None) if sig is not None: signal.signal(sig, signal.SIG_DFL) if start_new_session: os.setsid() try: if env is None: os.execvp(executable, args) else: # Python 3.6 started testing for # bytes values in the env; it also # started encoding strs using # fsencode and using a lower-level # API that takes a list of keys # and values. We don't have access # to that API, so we go the reverse direction. env = {os.fsdecode(k) if isinstance(k, bytes) else k: os.fsdecode(v) if isinstance(v, bytes) else v for k, v in env.items()} os.execvpe(executable, args, env) except OSError as e: e._failed_exec = True raise except: exc_type, exc_value, tb = sys.exc_info() # Save the traceback and attach it to the exception object exc_lines = traceback.format_exception(exc_type, exc_value, tb) exc_value.child_traceback = ''.join(exc_lines) os.write(errpipe_write, pickle.dumps(exc_value)) finally: # Make sure that the process exits no matter what. # The return code does not matter much as it won't be # reported to the application os._exit(1) # Parent self._child_created = True if gc_was_enabled: gc.enable() finally: # be sure the FD is closed no matter what os.close(errpipe_write) # self._devnull is not always defined. devnull_fd = getattr(self, '_devnull', None) if p2cread != -1 and p2cwrite != -1 and p2cread != devnull_fd: os.close(p2cread) if c2pwrite != -1 and c2pread != -1 and c2pwrite != devnull_fd: os.close(c2pwrite) if errwrite != -1 and errread != -1 and errwrite != devnull_fd: os.close(errwrite) if devnull_fd is not None: os.close(devnull_fd) # Prevent a double close of these fds from __init__ on error. self._closed_child_pipe_fds = True # Wait for exec to fail or succeed; possibly raising exception errpipe_read = FileObject(errpipe_read, 'rb') data = errpipe_read.read() finally: try: if hasattr(errpipe_read, 'close'): errpipe_read.close() else: os.close(errpipe_read) except OSError: # Especially on PyPy, we sometimes see the above # `os.close(errpipe_read)` raise an OSError. # It's not entirely clear why, but it happens in # InterprocessSignalTests.test_main sometimes, which must mean # we have some sort of race condition. pass finally: errpipe_read = -1 if data != b"": self.wait() child_exception = pickle.loads(data) for fd in (p2cwrite, c2pread, errread): if fd is not None and fd != -1: os.close(fd) if isinstance(child_exception, OSError): child_exception.filename = executable if hasattr(child_exception, '_failed_chdir'): child_exception.filename = cwd if getattr(child_exception, '_failed_chuser', False): child_exception.filename = None > raise child_exception E OSError: [Errno 8] Exec format error: 'locust' /usr/lib/python3/dist-packages/gevent/subprocess.py:1838: OSError _____________ StandaloneIntegrationTests.test_autostart_w_run_time _____________ self = @unittest.skipIf(sys.platform == "darwin", reason="This is too messy on macOS") def test_autostart_w_run_time(self): port = get_free_tcp_port() with mock_locustfile() as mocked: > proc = subprocess.Popen( [ "locust", "-f", mocked.file_path, "--web-port", str(port), "-t", "3", "--autostart", "--autoquit", "1", ], stdout=PIPE, stderr=PIPE, text=True, ) locust/test/test_main.py:635: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3/dist-packages/gevent/subprocess.py:808: in __init__ self._execute_child(args, executable, preexec_fn, close_fds, _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = args = ['locust', '-f', '/build/reproducible-path/locust-2.24.0/locust/test/mock_locustfile_1715256371_9909327_79485.py', '--web-port', '34561', '-t', ...] executable = 'locust', preexec_fn = None, close_fds = True, pass_fds = () cwd = None, env = None, universal_newlines = None, startupinfo = None creationflags = 0, shell = False, p2cread = -1, p2cwrite = -1, c2pread = 11 c2pwrite = 80, errread = 81, errwrite = 82, restore_signals = True, gid = None gids = None, uid = None, umask = -1, start_new_session = False process_group = None def _execute_child(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, universal_newlines, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, restore_signals, gid, gids, uid, umask, start_new_session, process_group): """Execute program (POSIX version)""" if isinstance(args, (str, bytes)): args = [args] elif isinstance(args, PathLike): if shell: raise TypeError('path-like args is not allowed when ' 'shell is true') args = [fsencode(args)] # os.PathLike -> [str] else: args = list(args) if shell: # On Android the default shell is at '/system/bin/sh'. unix_shell = ( '/system/bin/sh' if hasattr(sys, 'getandroidapilevel') else '/bin/sh' ) args = [unix_shell, "-c"] + args if executable: args[0] = executable if executable is None: executable = args[0] self._loop.install_sigchld() # For transferring possible exec failure from child to parent # The first char specifies the exception type: 0 means # OSError, 1 means some other error. errpipe_read, errpipe_write = self.pipe_cloexec() # errpipe_write must not be in the standard io 0, 1, or 2 fd range. low_fds_to_close = [] while errpipe_write < 3: low_fds_to_close.append(errpipe_write) errpipe_write = os.dup(errpipe_write) for low_fd in low_fds_to_close: os.close(low_fd) try: try: gc_was_enabled = gc.isenabled() # Disable gc to avoid bug where gc -> file_dealloc -> # write to stderr -> hang. http://bugs.python.org/issue1336 gc.disable() try: self.pid = fork_and_watch(self._on_child, self._loop, True, fork) except: if gc_was_enabled: gc.enable() raise if self.pid == 0: # Child # In various places on the child side of things, we catch OSError # and add attributes to it that detail where in the process we failed; # like all exceptions until we have exec'd, this exception is pickled # and sent to the parent to raise in the calling process. # The parent uses this to decide how to treat that exception, # adjusting certain information about it as needed. # # Python 3.11.8 --- yes, a minor patch release --- stopped # letting the 'filename' parameter get set in the resulting # exception for many cases. We're not quite interpreting this # the same way the stdlib is, I'm sure, but this makes the stdlib # tests pass. # XXX: Technically we're doing a lot of stuff here that # may not be safe to do before a exec(), depending on the OS. # CPython 3 goes to great lengths to precompute a lot # of this info before the fork and pass it all to C functions that # try hard not to call things like malloc(). (Of course, # CPython 2 pretty much did what we're doing.) try: # Close parent's pipe ends if p2cwrite != -1: os.close(p2cwrite) if c2pread != -1: os.close(c2pread) if errread != -1: os.close(errread) os.close(errpipe_read) # When duping fds, if there arises a situation # where one of the fds is either 0, 1 or 2, it # is possible that it is overwritten (#12607). if c2pwrite == 0: c2pwrite = os.dup(c2pwrite) _set_inheritable(c2pwrite, False) while errwrite in (0, 1): errwrite = os.dup(errwrite) _set_inheritable(errwrite, False) # Dup fds for child def _dup2(existing, desired): # dup2() removes the CLOEXEC flag but # we must do it ourselves if dup2() # would be a no-op (issue #10806). if existing == desired: self._set_cloexec_flag(existing, False) elif existing != -1: os.dup2(existing, desired) try: self._remove_nonblock_flag(desired) except OSError: # Ignore EBADF, it may not actually be # open yet. # Tested beginning in 3.7.0b3 test_subprocess.py pass _dup2(p2cread, 0) _dup2(c2pwrite, 1) _dup2(errwrite, 2) # Close pipe fds. Make sure we don't close the # same fd more than once, or standard fds. if not True: closed = set([None]) for fd in (p2cread, c2pwrite, errwrite): if fd not in closed and fd > 2: os.close(fd) closed.add(fd) # Python 3 (with a working set_inheritable): # We no longer manually close p2cread, # c2pwrite, and errwrite here as # _close_open_fds takes care when it is # not already non-inheritable. if cwd is not None: try: os.chdir(cwd) except OSError as e: e._failed_chdir = True raise # Python 3.9 if umask >= 0: os.umask(umask) # XXX: CPython does _Py_RestoreSignals here. # Then setsid() based on ??? try: if gids: os.setgroups(gids) if gid: os.setregid(gid, gid) if uid: os.setreuid(uid, uid) if process_group is not None: os.setpgid(0, process_group) except OSError as e: e._failed_chuser = True raise if preexec_fn: preexec_fn() # Close all other fds, if asked for. This must be done # after preexec_fn runs. if close_fds: fds_to_keep = set(pass_fds) fds_to_keep.add(errpipe_write) self._close_fds(fds_to_keep, errpipe_write) if restore_signals: # restore the documented signals back to sig_dfl; # not all will be defined on every platform for sig in 'SIGPIPE', 'SIGXFZ', 'SIGXFSZ': sig = getattr(signal, sig, None) if sig is not None: signal.signal(sig, signal.SIG_DFL) if start_new_session: os.setsid() try: if env is None: os.execvp(executable, args) else: # Python 3.6 started testing for # bytes values in the env; it also # started encoding strs using # fsencode and using a lower-level # API that takes a list of keys # and values. We don't have access # to that API, so we go the reverse direction. env = {os.fsdecode(k) if isinstance(k, bytes) else k: os.fsdecode(v) if isinstance(v, bytes) else v for k, v in env.items()} os.execvpe(executable, args, env) except OSError as e: e._failed_exec = True raise except: exc_type, exc_value, tb = sys.exc_info() # Save the traceback and attach it to the exception object exc_lines = traceback.format_exception(exc_type, exc_value, tb) exc_value.child_traceback = ''.join(exc_lines) os.write(errpipe_write, pickle.dumps(exc_value)) finally: # Make sure that the process exits no matter what. # The return code does not matter much as it won't be # reported to the application os._exit(1) # Parent self._child_created = True if gc_was_enabled: gc.enable() finally: # be sure the FD is closed no matter what os.close(errpipe_write) # self._devnull is not always defined. devnull_fd = getattr(self, '_devnull', None) if p2cread != -1 and p2cwrite != -1 and p2cread != devnull_fd: os.close(p2cread) if c2pwrite != -1 and c2pread != -1 and c2pwrite != devnull_fd: os.close(c2pwrite) if errwrite != -1 and errread != -1 and errwrite != devnull_fd: os.close(errwrite) if devnull_fd is not None: os.close(devnull_fd) # Prevent a double close of these fds from __init__ on error. self._closed_child_pipe_fds = True # Wait for exec to fail or succeed; possibly raising exception errpipe_read = FileObject(errpipe_read, 'rb') data = errpipe_read.read() finally: try: if hasattr(errpipe_read, 'close'): errpipe_read.close() else: os.close(errpipe_read) except OSError: # Especially on PyPy, we sometimes see the above # `os.close(errpipe_read)` raise an OSError. # It's not entirely clear why, but it happens in # InterprocessSignalTests.test_main sometimes, which must mean # we have some sort of race condition. pass finally: errpipe_read = -1 if data != b"": self.wait() child_exception = pickle.loads(data) for fd in (p2cwrite, c2pread, errread): if fd is not None and fd != -1: os.close(fd) if isinstance(child_exception, OSError): child_exception.filename = executable if hasattr(child_exception, '_failed_chdir'): child_exception.filename = cwd if getattr(child_exception, '_failed_chuser', False): child_exception.filename = None > raise child_exception E OSError: [Errno 8] Exec format error: 'locust' /usr/lib/python3/dist-packages/gevent/subprocess.py:1838: OSError ____________ StandaloneIntegrationTests.test_autostart_wo_run_time _____________ self = @unittest.skipIf(os.name == "nt", reason="Signal handling on windows is hard") def test_autostart_wo_run_time(self): port = get_free_tcp_port() with mock_locustfile() as mocked: > proc = subprocess.Popen( [ "locust", "-f", mocked.file_path, "--web-port", str(port), "--autostart", ], stdout=PIPE, stderr=PIPE, text=True, ) locust/test/test_main.py:600: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3/dist-packages/gevent/subprocess.py:808: in __init__ self._execute_child(args, executable, preexec_fn, close_fds, _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = args = ['locust', '-f', '/build/reproducible-path/locust-2.24.0/locust/test/mock_locustfile_1715256372_2570724_14656.py', '--web-port', '33621', '--autostart'] executable = 'locust', preexec_fn = None, close_fds = True, pass_fds = () cwd = None, env = None, universal_newlines = None, startupinfo = None creationflags = 0, shell = False, p2cread = -1, p2cwrite = -1, c2pread = 11 c2pwrite = 80, errread = 81, errwrite = 82, restore_signals = True, gid = None gids = None, uid = None, umask = -1, start_new_session = False process_group = None def _execute_child(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, universal_newlines, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, restore_signals, gid, gids, uid, umask, start_new_session, process_group): """Execute program (POSIX version)""" if isinstance(args, (str, bytes)): args = [args] elif isinstance(args, PathLike): if shell: raise TypeError('path-like args is not allowed when ' 'shell is true') args = [fsencode(args)] # os.PathLike -> [str] else: args = list(args) if shell: # On Android the default shell is at '/system/bin/sh'. unix_shell = ( '/system/bin/sh' if hasattr(sys, 'getandroidapilevel') else '/bin/sh' ) args = [unix_shell, "-c"] + args if executable: args[0] = executable if executable is None: executable = args[0] self._loop.install_sigchld() # For transferring possible exec failure from child to parent # The first char specifies the exception type: 0 means # OSError, 1 means some other error. errpipe_read, errpipe_write = self.pipe_cloexec() # errpipe_write must not be in the standard io 0, 1, or 2 fd range. low_fds_to_close = [] while errpipe_write < 3: low_fds_to_close.append(errpipe_write) errpipe_write = os.dup(errpipe_write) for low_fd in low_fds_to_close: os.close(low_fd) try: try: gc_was_enabled = gc.isenabled() # Disable gc to avoid bug where gc -> file_dealloc -> # write to stderr -> hang. http://bugs.python.org/issue1336 gc.disable() try: self.pid = fork_and_watch(self._on_child, self._loop, True, fork) except: if gc_was_enabled: gc.enable() raise if self.pid == 0: # Child # In various places on the child side of things, we catch OSError # and add attributes to it that detail where in the process we failed; # like all exceptions until we have exec'd, this exception is pickled # and sent to the parent to raise in the calling process. # The parent uses this to decide how to treat that exception, # adjusting certain information about it as needed. # # Python 3.11.8 --- yes, a minor patch release --- stopped # letting the 'filename' parameter get set in the resulting # exception for many cases. We're not quite interpreting this # the same way the stdlib is, I'm sure, but this makes the stdlib # tests pass. # XXX: Technically we're doing a lot of stuff here that # may not be safe to do before a exec(), depending on the OS. # CPython 3 goes to great lengths to precompute a lot # of this info before the fork and pass it all to C functions that # try hard not to call things like malloc(). (Of course, # CPython 2 pretty much did what we're doing.) try: # Close parent's pipe ends if p2cwrite != -1: os.close(p2cwrite) if c2pread != -1: os.close(c2pread) if errread != -1: os.close(errread) os.close(errpipe_read) # When duping fds, if there arises a situation # where one of the fds is either 0, 1 or 2, it # is possible that it is overwritten (#12607). if c2pwrite == 0: c2pwrite = os.dup(c2pwrite) _set_inheritable(c2pwrite, False) while errwrite in (0, 1): errwrite = os.dup(errwrite) _set_inheritable(errwrite, False) # Dup fds for child def _dup2(existing, desired): # dup2() removes the CLOEXEC flag but # we must do it ourselves if dup2() # would be a no-op (issue #10806). if existing == desired: self._set_cloexec_flag(existing, False) elif existing != -1: os.dup2(existing, desired) try: self._remove_nonblock_flag(desired) except OSError: # Ignore EBADF, it may not actually be # open yet. # Tested beginning in 3.7.0b3 test_subprocess.py pass _dup2(p2cread, 0) _dup2(c2pwrite, 1) _dup2(errwrite, 2) # Close pipe fds. Make sure we don't close the # same fd more than once, or standard fds. if not True: closed = set([None]) for fd in (p2cread, c2pwrite, errwrite): if fd not in closed and fd > 2: os.close(fd) closed.add(fd) # Python 3 (with a working set_inheritable): # We no longer manually close p2cread, # c2pwrite, and errwrite here as # _close_open_fds takes care when it is # not already non-inheritable. if cwd is not None: try: os.chdir(cwd) except OSError as e: e._failed_chdir = True raise # Python 3.9 if umask >= 0: os.umask(umask) # XXX: CPython does _Py_RestoreSignals here. # Then setsid() based on ??? try: if gids: os.setgroups(gids) if gid: os.setregid(gid, gid) if uid: os.setreuid(uid, uid) if process_group is not None: os.setpgid(0, process_group) except OSError as e: e._failed_chuser = True raise if preexec_fn: preexec_fn() # Close all other fds, if asked for. This must be done # after preexec_fn runs. if close_fds: fds_to_keep = set(pass_fds) fds_to_keep.add(errpipe_write) self._close_fds(fds_to_keep, errpipe_write) if restore_signals: # restore the documented signals back to sig_dfl; # not all will be defined on every platform for sig in 'SIGPIPE', 'SIGXFZ', 'SIGXFSZ': sig = getattr(signal, sig, None) if sig is not None: signal.signal(sig, signal.SIG_DFL) if start_new_session: os.setsid() try: if env is None: os.execvp(executable, args) else: # Python 3.6 started testing for # bytes values in the env; it also # started encoding strs using # fsencode and using a lower-level # API that takes a list of keys # and values. We don't have access # to that API, so we go the reverse direction. env = {os.fsdecode(k) if isinstance(k, bytes) else k: os.fsdecode(v) if isinstance(v, bytes) else v for k, v in env.items()} os.execvpe(executable, args, env) except OSError as e: e._failed_exec = True raise except: exc_type, exc_value, tb = sys.exc_info() # Save the traceback and attach it to the exception object exc_lines = traceback.format_exception(exc_type, exc_value, tb) exc_value.child_traceback = ''.join(exc_lines) os.write(errpipe_write, pickle.dumps(exc_value)) finally: # Make sure that the process exits no matter what. # The return code does not matter much as it won't be # reported to the application os._exit(1) # Parent self._child_created = True if gc_was_enabled: gc.enable() finally: # be sure the FD is closed no matter what os.close(errpipe_write) # self._devnull is not always defined. devnull_fd = getattr(self, '_devnull', None) if p2cread != -1 and p2cwrite != -1 and p2cread != devnull_fd: os.close(p2cread) if c2pwrite != -1 and c2pread != -1 and c2pwrite != devnull_fd: os.close(c2pwrite) if errwrite != -1 and errread != -1 and errwrite != devnull_fd: os.close(errwrite) if devnull_fd is not None: os.close(devnull_fd) # Prevent a double close of these fds from __init__ on error. self._closed_child_pipe_fds = True # Wait for exec to fail or succeed; possibly raising exception errpipe_read = FileObject(errpipe_read, 'rb') data = errpipe_read.read() finally: try: if hasattr(errpipe_read, 'close'): errpipe_read.close() else: os.close(errpipe_read) except OSError: # Especially on PyPy, we sometimes see the above # `os.close(errpipe_read)` raise an OSError. # It's not entirely clear why, but it happens in # InterprocessSignalTests.test_main sometimes, which must mean # we have some sort of race condition. pass finally: errpipe_read = -1 if data != b"": self.wait() child_exception = pickle.loads(data) for fd in (p2cwrite, c2pread, errread): if fd is not None and fd != -1: os.close(fd) if isinstance(child_exception, OSError): child_exception.filename = executable if hasattr(child_exception, '_failed_chdir'): child_exception.filename = cwd if getattr(child_exception, '_failed_chuser', False): child_exception.filename = None > raise child_exception E OSError: [Errno 8] Exec format error: 'locust' /usr/lib/python3/dist-packages/gevent/subprocess.py:1838: OSError _________ StandaloneIntegrationTests.test_command_line_user_selection __________ self = def test_command_line_user_selection(self): LOCUSTFILE_CONTENT = textwrap.dedent( """ from locust import User, task, constant class User1(User): wait_time = constant(1) @task def t(self): print("User1 is running") class User2(User): wait_time = constant(1) @task def t(self): print("User2 is running") class User3(User): wait_time = constant(1) @task def t(self): print("User3 is running") """ ) with mock_locustfile(content=LOCUSTFILE_CONTENT) as mocked: proc = subprocess.Popen( " ".join( [ "locust", "-f", mocked.file_path, "--headless", "--run-time", "2s", "-u", "5", "-r", "10", "User2", "User3", ] ), stderr=STDOUT, stdout=PIPE, shell=True, text=True, ) output = proc.communicate()[0] self.assertNotIn("User1 is running", output) > self.assertIn("User2 is running", output) E AssertionError: 'User2 is running' not found in '/build/reproducible-path/locust-2.24.0/debian/locust: line 2: from: command not found\n/build/reproducible-path/locust-2.24.0/debian/locust: line 5: syntax error: unexpected end of file\n' locust/test/test_main.py:1080: AssertionError _______________ StandaloneIntegrationTests.test_custom_arguments _______________ self = @unittest.skipIf(os.name == "nt", reason="Signal handling on windows is hard") def test_custom_arguments(self): port = get_free_tcp_port() with temporary_file( content=textwrap.dedent( """ from locust import User, task, constant, events @events.init_command_line_parser.add_listener def _(parser, **kw): parser.add_argument("--custom-string-arg") class TestUser(User): wait_time = constant(10) @task def my_task(self): print(self.environment.parsed_options.custom_string_arg) """ ) ) as file_path: # print(subprocess.check_output(["cat", file_path])) > proc = subprocess.Popen( ["locust", "-f", file_path, "--custom-string-arg", "command_line_value", "--web-port", str(port)], stdout=PIPE, stderr=PIPE, text=True, ) locust/test/test_main.py:104: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3/dist-packages/gevent/subprocess.py:808: in __init__ self._execute_child(args, executable, preexec_fn, close_fds, _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = args = ['locust', '-f', '/tmp/tmp2ycgniqr_locustfile.py', '--custom-string-arg', 'command_line_value', '--web-port', ...] executable = 'locust', preexec_fn = None, close_fds = True, pass_fds = () cwd = None, env = None, universal_newlines = None, startupinfo = None creationflags = 0, shell = False, p2cread = -1, p2cwrite = -1, c2pread = 11 c2pwrite = 80, errread = 81, errwrite = 82, restore_signals = True, gid = None gids = None, uid = None, umask = -1, start_new_session = False process_group = None def _execute_child(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, universal_newlines, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, restore_signals, gid, gids, uid, umask, start_new_session, process_group): """Execute program (POSIX version)""" if isinstance(args, (str, bytes)): args = [args] elif isinstance(args, PathLike): if shell: raise TypeError('path-like args is not allowed when ' 'shell is true') args = [fsencode(args)] # os.PathLike -> [str] else: args = list(args) if shell: # On Android the default shell is at '/system/bin/sh'. unix_shell = ( '/system/bin/sh' if hasattr(sys, 'getandroidapilevel') else '/bin/sh' ) args = [unix_shell, "-c"] + args if executable: args[0] = executable if executable is None: executable = args[0] self._loop.install_sigchld() # For transferring possible exec failure from child to parent # The first char specifies the exception type: 0 means # OSError, 1 means some other error. errpipe_read, errpipe_write = self.pipe_cloexec() # errpipe_write must not be in the standard io 0, 1, or 2 fd range. low_fds_to_close = [] while errpipe_write < 3: low_fds_to_close.append(errpipe_write) errpipe_write = os.dup(errpipe_write) for low_fd in low_fds_to_close: os.close(low_fd) try: try: gc_was_enabled = gc.isenabled() # Disable gc to avoid bug where gc -> file_dealloc -> # write to stderr -> hang. http://bugs.python.org/issue1336 gc.disable() try: self.pid = fork_and_watch(self._on_child, self._loop, True, fork) except: if gc_was_enabled: gc.enable() raise if self.pid == 0: # Child # In various places on the child side of things, we catch OSError # and add attributes to it that detail where in the process we failed; # like all exceptions until we have exec'd, this exception is pickled # and sent to the parent to raise in the calling process. # The parent uses this to decide how to treat that exception, # adjusting certain information about it as needed. # # Python 3.11.8 --- yes, a minor patch release --- stopped # letting the 'filename' parameter get set in the resulting # exception for many cases. We're not quite interpreting this # the same way the stdlib is, I'm sure, but this makes the stdlib # tests pass. # XXX: Technically we're doing a lot of stuff here that # may not be safe to do before a exec(), depending on the OS. # CPython 3 goes to great lengths to precompute a lot # of this info before the fork and pass it all to C functions that # try hard not to call things like malloc(). (Of course, # CPython 2 pretty much did what we're doing.) try: # Close parent's pipe ends if p2cwrite != -1: os.close(p2cwrite) if c2pread != -1: os.close(c2pread) if errread != -1: os.close(errread) os.close(errpipe_read) # When duping fds, if there arises a situation # where one of the fds is either 0, 1 or 2, it # is possible that it is overwritten (#12607). if c2pwrite == 0: c2pwrite = os.dup(c2pwrite) _set_inheritable(c2pwrite, False) while errwrite in (0, 1): errwrite = os.dup(errwrite) _set_inheritable(errwrite, False) # Dup fds for child def _dup2(existing, desired): # dup2() removes the CLOEXEC flag but # we must do it ourselves if dup2() # would be a no-op (issue #10806). if existing == desired: self._set_cloexec_flag(existing, False) elif existing != -1: os.dup2(existing, desired) try: self._remove_nonblock_flag(desired) except OSError: # Ignore EBADF, it may not actually be # open yet. # Tested beginning in 3.7.0b3 test_subprocess.py pass _dup2(p2cread, 0) _dup2(c2pwrite, 1) _dup2(errwrite, 2) # Close pipe fds. Make sure we don't close the # same fd more than once, or standard fds. if not True: closed = set([None]) for fd in (p2cread, c2pwrite, errwrite): if fd not in closed and fd > 2: os.close(fd) closed.add(fd) # Python 3 (with a working set_inheritable): # We no longer manually close p2cread, # c2pwrite, and errwrite here as # _close_open_fds takes care when it is # not already non-inheritable. if cwd is not None: try: os.chdir(cwd) except OSError as e: e._failed_chdir = True raise # Python 3.9 if umask >= 0: os.umask(umask) # XXX: CPython does _Py_RestoreSignals here. # Then setsid() based on ??? try: if gids: os.setgroups(gids) if gid: os.setregid(gid, gid) if uid: os.setreuid(uid, uid) if process_group is not None: os.setpgid(0, process_group) except OSError as e: e._failed_chuser = True raise if preexec_fn: preexec_fn() # Close all other fds, if asked for. This must be done # after preexec_fn runs. if close_fds: fds_to_keep = set(pass_fds) fds_to_keep.add(errpipe_write) self._close_fds(fds_to_keep, errpipe_write) if restore_signals: # restore the documented signals back to sig_dfl; # not all will be defined on every platform for sig in 'SIGPIPE', 'SIGXFZ', 'SIGXFSZ': sig = getattr(signal, sig, None) if sig is not None: signal.signal(sig, signal.SIG_DFL) if start_new_session: os.setsid() try: if env is None: os.execvp(executable, args) else: # Python 3.6 started testing for # bytes values in the env; it also # started encoding strs using # fsencode and using a lower-level # API that takes a list of keys # and values. We don't have access # to that API, so we go the reverse direction. env = {os.fsdecode(k) if isinstance(k, bytes) else k: os.fsdecode(v) if isinstance(v, bytes) else v for k, v in env.items()} os.execvpe(executable, args, env) except OSError as e: e._failed_exec = True raise except: exc_type, exc_value, tb = sys.exc_info() # Save the traceback and attach it to the exception object exc_lines = traceback.format_exception(exc_type, exc_value, tb) exc_value.child_traceback = ''.join(exc_lines) os.write(errpipe_write, pickle.dumps(exc_value)) finally: # Make sure that the process exits no matter what. # The return code does not matter much as it won't be # reported to the application os._exit(1) # Parent self._child_created = True if gc_was_enabled: gc.enable() finally: # be sure the FD is closed no matter what os.close(errpipe_write) # self._devnull is not always defined. devnull_fd = getattr(self, '_devnull', None) if p2cread != -1 and p2cwrite != -1 and p2cread != devnull_fd: os.close(p2cread) if c2pwrite != -1 and c2pread != -1 and c2pwrite != devnull_fd: os.close(c2pwrite) if errwrite != -1 and errread != -1 and errwrite != devnull_fd: os.close(errwrite) if devnull_fd is not None: os.close(devnull_fd) # Prevent a double close of these fds from __init__ on error. self._closed_child_pipe_fds = True # Wait for exec to fail or succeed; possibly raising exception errpipe_read = FileObject(errpipe_read, 'rb') data = errpipe_read.read() finally: try: if hasattr(errpipe_read, 'close'): errpipe_read.close() else: os.close(errpipe_read) except OSError: # Especially on PyPy, we sometimes see the above # `os.close(errpipe_read)` raise an OSError. # It's not entirely clear why, but it happens in # InterprocessSignalTests.test_main sometimes, which must mean # we have some sort of race condition. pass finally: errpipe_read = -1 if data != b"": self.wait() child_exception = pickle.loads(data) for fd in (p2cwrite, c2pread, errread): if fd is not None and fd != -1: os.close(fd) if isinstance(child_exception, OSError): child_exception.filename = executable if hasattr(child_exception, '_failed_chdir'): child_exception.filename = cwd if getattr(child_exception, '_failed_chuser', False): child_exception.filename = None > raise child_exception E OSError: [Errno 8] Exec format error: 'locust' /usr/lib/python3/dist-packages/gevent/subprocess.py:1838: OSError ___________ StandaloneIntegrationTests.test_custom_arguments_in_file ___________ self = @unittest.skipIf(os.name == "nt", reason="Signal handling on windows is hard") def test_custom_arguments_in_file(self): with temporary_file( content=textwrap.dedent( """ from locust import User, task, constant, events @events.init_command_line_parser.add_listener def _(parser, **kw): parser.add_argument("--custom-string-arg") class TestUser(User): wait_time = constant(10) @task def my_task(self): print(self.environment.parsed_options.custom_string_arg) """ ) ) as file_path: try: with open("locust.conf", "w") as conf_file: conf_file.write("custom-string-arg config_file_value") > proc = subprocess.Popen( ["locust", "-f", file_path, "--autostart"], stdout=PIPE, stderr=PIPE, text=True, ) locust/test/test_main.py:147: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3/dist-packages/gevent/subprocess.py:808: in __init__ self._execute_child(args, executable, preexec_fn, close_fds, _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = args = ['locust', '-f', '/tmp/tmpsh_a7my8_locustfile.py', '--autostart'] executable = 'locust', preexec_fn = None, close_fds = True, pass_fds = () cwd = None, env = None, universal_newlines = None, startupinfo = None creationflags = 0, shell = False, p2cread = -1, p2cwrite = -1, c2pread = 11 c2pwrite = 80, errread = 81, errwrite = 82, restore_signals = True, gid = None gids = None, uid = None, umask = -1, start_new_session = False process_group = None def _execute_child(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, universal_newlines, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, restore_signals, gid, gids, uid, umask, start_new_session, process_group): """Execute program (POSIX version)""" if isinstance(args, (str, bytes)): args = [args] elif isinstance(args, PathLike): if shell: raise TypeError('path-like args is not allowed when ' 'shell is true') args = [fsencode(args)] # os.PathLike -> [str] else: args = list(args) if shell: # On Android the default shell is at '/system/bin/sh'. unix_shell = ( '/system/bin/sh' if hasattr(sys, 'getandroidapilevel') else '/bin/sh' ) args = [unix_shell, "-c"] + args if executable: args[0] = executable if executable is None: executable = args[0] self._loop.install_sigchld() # For transferring possible exec failure from child to parent # The first char specifies the exception type: 0 means # OSError, 1 means some other error. errpipe_read, errpipe_write = self.pipe_cloexec() # errpipe_write must not be in the standard io 0, 1, or 2 fd range. low_fds_to_close = [] while errpipe_write < 3: low_fds_to_close.append(errpipe_write) errpipe_write = os.dup(errpipe_write) for low_fd in low_fds_to_close: os.close(low_fd) try: try: gc_was_enabled = gc.isenabled() # Disable gc to avoid bug where gc -> file_dealloc -> # write to stderr -> hang. http://bugs.python.org/issue1336 gc.disable() try: self.pid = fork_and_watch(self._on_child, self._loop, True, fork) except: if gc_was_enabled: gc.enable() raise if self.pid == 0: # Child # In various places on the child side of things, we catch OSError # and add attributes to it that detail where in the process we failed; # like all exceptions until we have exec'd, this exception is pickled # and sent to the parent to raise in the calling process. # The parent uses this to decide how to treat that exception, # adjusting certain information about it as needed. # # Python 3.11.8 --- yes, a minor patch release --- stopped # letting the 'filename' parameter get set in the resulting # exception for many cases. We're not quite interpreting this # the same way the stdlib is, I'm sure, but this makes the stdlib # tests pass. # XXX: Technically we're doing a lot of stuff here that # may not be safe to do before a exec(), depending on the OS. # CPython 3 goes to great lengths to precompute a lot # of this info before the fork and pass it all to C functions that # try hard not to call things like malloc(). (Of course, # CPython 2 pretty much did what we're doing.) try: # Close parent's pipe ends if p2cwrite != -1: os.close(p2cwrite) if c2pread != -1: os.close(c2pread) if errread != -1: os.close(errread) os.close(errpipe_read) # When duping fds, if there arises a situation # where one of the fds is either 0, 1 or 2, it # is possible that it is overwritten (#12607). if c2pwrite == 0: c2pwrite = os.dup(c2pwrite) _set_inheritable(c2pwrite, False) while errwrite in (0, 1): errwrite = os.dup(errwrite) _set_inheritable(errwrite, False) # Dup fds for child def _dup2(existing, desired): # dup2() removes the CLOEXEC flag but # we must do it ourselves if dup2() # would be a no-op (issue #10806). if existing == desired: self._set_cloexec_flag(existing, False) elif existing != -1: os.dup2(existing, desired) try: self._remove_nonblock_flag(desired) except OSError: # Ignore EBADF, it may not actually be # open yet. # Tested beginning in 3.7.0b3 test_subprocess.py pass _dup2(p2cread, 0) _dup2(c2pwrite, 1) _dup2(errwrite, 2) # Close pipe fds. Make sure we don't close the # same fd more than once, or standard fds. if not True: closed = set([None]) for fd in (p2cread, c2pwrite, errwrite): if fd not in closed and fd > 2: os.close(fd) closed.add(fd) # Python 3 (with a working set_inheritable): # We no longer manually close p2cread, # c2pwrite, and errwrite here as # _close_open_fds takes care when it is # not already non-inheritable. if cwd is not None: try: os.chdir(cwd) except OSError as e: e._failed_chdir = True raise # Python 3.9 if umask >= 0: os.umask(umask) # XXX: CPython does _Py_RestoreSignals here. # Then setsid() based on ??? try: if gids: os.setgroups(gids) if gid: os.setregid(gid, gid) if uid: os.setreuid(uid, uid) if process_group is not None: os.setpgid(0, process_group) except OSError as e: e._failed_chuser = True raise if preexec_fn: preexec_fn() # Close all other fds, if asked for. This must be done # after preexec_fn runs. if close_fds: fds_to_keep = set(pass_fds) fds_to_keep.add(errpipe_write) self._close_fds(fds_to_keep, errpipe_write) if restore_signals: # restore the documented signals back to sig_dfl; # not all will be defined on every platform for sig in 'SIGPIPE', 'SIGXFZ', 'SIGXFSZ': sig = getattr(signal, sig, None) if sig is not None: signal.signal(sig, signal.SIG_DFL) if start_new_session: os.setsid() try: if env is None: os.execvp(executable, args) else: # Python 3.6 started testing for # bytes values in the env; it also # started encoding strs using # fsencode and using a lower-level # API that takes a list of keys # and values. We don't have access # to that API, so we go the reverse direction. env = {os.fsdecode(k) if isinstance(k, bytes) else k: os.fsdecode(v) if isinstance(v, bytes) else v for k, v in env.items()} os.execvpe(executable, args, env) except OSError as e: e._failed_exec = True raise except: exc_type, exc_value, tb = sys.exc_info() # Save the traceback and attach it to the exception object exc_lines = traceback.format_exception(exc_type, exc_value, tb) exc_value.child_traceback = ''.join(exc_lines) os.write(errpipe_write, pickle.dumps(exc_value)) finally: # Make sure that the process exits no matter what. # The return code does not matter much as it won't be # reported to the application os._exit(1) # Parent self._child_created = True if gc_was_enabled: gc.enable() finally: # be sure the FD is closed no matter what os.close(errpipe_write) # self._devnull is not always defined. devnull_fd = getattr(self, '_devnull', None) if p2cread != -1 and p2cwrite != -1 and p2cread != devnull_fd: os.close(p2cread) if c2pwrite != -1 and c2pread != -1 and c2pwrite != devnull_fd: os.close(c2pwrite) if errwrite != -1 and errread != -1 and errwrite != devnull_fd: os.close(errwrite) if devnull_fd is not None: os.close(devnull_fd) # Prevent a double close of these fds from __init__ on error. self._closed_child_pipe_fds = True # Wait for exec to fail or succeed; possibly raising exception errpipe_read = FileObject(errpipe_read, 'rb') data = errpipe_read.read() finally: try: if hasattr(errpipe_read, 'close'): errpipe_read.close() else: os.close(errpipe_read) except OSError: # Especially on PyPy, we sometimes see the above # `os.close(errpipe_read)` raise an OSError. # It's not entirely clear why, but it happens in # InterprocessSignalTests.test_main sometimes, which must mean # we have some sort of race condition. pass finally: errpipe_read = -1 if data != b"": self.wait() child_exception = pickle.loads(data) for fd in (p2cwrite, c2pread, errread): if fd is not None and fd != -1: os.close(fd) if isinstance(child_exception, OSError): child_exception.filename = executable if hasattr(child_exception, '_failed_chdir'): child_exception.filename = cwd if getattr(child_exception, '_failed_chuser', False): child_exception.filename = None > raise child_exception E OSError: [Errno 8] Exec format error: 'locust' /usr/lib/python3/dist-packages/gevent/subprocess.py:1838: OSError _______________ StandaloneIntegrationTests.test_custom_exit_code _______________ self = @unittest.skipIf(os.name == "nt", reason="Signal handling on windows is hard") def test_custom_exit_code(self): with temporary_file( content=textwrap.dedent( """ from locust import User, task, constant, events @events.quitting.add_listener def _(environment, **kw): environment.process_exit_code = 42 @events.quit.add_listener def _(exit_code, **kw): print(f"Exit code in quit event {exit_code}") class TestUser(User): wait_time = constant(3) @task def my_task(self): print("running my_task()") """ ) ) as file_path: > proc = subprocess.Popen(["locust", "-f", file_path], stdout=PIPE, stderr=PIPE, text=True) locust/test/test_main.py:182: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3/dist-packages/gevent/subprocess.py:808: in __init__ self._execute_child(args, executable, preexec_fn, close_fds, _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = args = ['locust', '-f', '/tmp/tmpgbn1f7qk_locustfile.py'], executable = 'locust' preexec_fn = None, close_fds = True, pass_fds = (), cwd = None, env = None universal_newlines = None, startupinfo = None, creationflags = 0, shell = False p2cread = -1, p2cwrite = -1, c2pread = 11, c2pwrite = 80, errread = 81 errwrite = 82, restore_signals = True, gid = None, gids = None, uid = None umask = -1, start_new_session = False, process_group = None def _execute_child(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, universal_newlines, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, restore_signals, gid, gids, uid, umask, start_new_session, process_group): """Execute program (POSIX version)""" if isinstance(args, (str, bytes)): args = [args] elif isinstance(args, PathLike): if shell: raise TypeError('path-like args is not allowed when ' 'shell is true') args = [fsencode(args)] # os.PathLike -> [str] else: args = list(args) if shell: # On Android the default shell is at '/system/bin/sh'. unix_shell = ( '/system/bin/sh' if hasattr(sys, 'getandroidapilevel') else '/bin/sh' ) args = [unix_shell, "-c"] + args if executable: args[0] = executable if executable is None: executable = args[0] self._loop.install_sigchld() # For transferring possible exec failure from child to parent # The first char specifies the exception type: 0 means # OSError, 1 means some other error. errpipe_read, errpipe_write = self.pipe_cloexec() # errpipe_write must not be in the standard io 0, 1, or 2 fd range. low_fds_to_close = [] while errpipe_write < 3: low_fds_to_close.append(errpipe_write) errpipe_write = os.dup(errpipe_write) for low_fd in low_fds_to_close: os.close(low_fd) try: try: gc_was_enabled = gc.isenabled() # Disable gc to avoid bug where gc -> file_dealloc -> # write to stderr -> hang. http://bugs.python.org/issue1336 gc.disable() try: self.pid = fork_and_watch(self._on_child, self._loop, True, fork) except: if gc_was_enabled: gc.enable() raise if self.pid == 0: # Child # In various places on the child side of things, we catch OSError # and add attributes to it that detail where in the process we failed; # like all exceptions until we have exec'd, this exception is pickled # and sent to the parent to raise in the calling process. # The parent uses this to decide how to treat that exception, # adjusting certain information about it as needed. # # Python 3.11.8 --- yes, a minor patch release --- stopped # letting the 'filename' parameter get set in the resulting # exception for many cases. We're not quite interpreting this # the same way the stdlib is, I'm sure, but this makes the stdlib # tests pass. # XXX: Technically we're doing a lot of stuff here that # may not be safe to do before a exec(), depending on the OS. # CPython 3 goes to great lengths to precompute a lot # of this info before the fork and pass it all to C functions that # try hard not to call things like malloc(). (Of course, # CPython 2 pretty much did what we're doing.) try: # Close parent's pipe ends if p2cwrite != -1: os.close(p2cwrite) if c2pread != -1: os.close(c2pread) if errread != -1: os.close(errread) os.close(errpipe_read) # When duping fds, if there arises a situation # where one of the fds is either 0, 1 or 2, it # is possible that it is overwritten (#12607). if c2pwrite == 0: c2pwrite = os.dup(c2pwrite) _set_inheritable(c2pwrite, False) while errwrite in (0, 1): errwrite = os.dup(errwrite) _set_inheritable(errwrite, False) # Dup fds for child def _dup2(existing, desired): # dup2() removes the CLOEXEC flag but # we must do it ourselves if dup2() # would be a no-op (issue #10806). if existing == desired: self._set_cloexec_flag(existing, False) elif existing != -1: os.dup2(existing, desired) try: self._remove_nonblock_flag(desired) except OSError: # Ignore EBADF, it may not actually be # open yet. # Tested beginning in 3.7.0b3 test_subprocess.py pass _dup2(p2cread, 0) _dup2(c2pwrite, 1) _dup2(errwrite, 2) # Close pipe fds. Make sure we don't close the # same fd more than once, or standard fds. if not True: closed = set([None]) for fd in (p2cread, c2pwrite, errwrite): if fd not in closed and fd > 2: os.close(fd) closed.add(fd) # Python 3 (with a working set_inheritable): # We no longer manually close p2cread, # c2pwrite, and errwrite here as # _close_open_fds takes care when it is # not already non-inheritable. if cwd is not None: try: os.chdir(cwd) except OSError as e: e._failed_chdir = True raise # Python 3.9 if umask >= 0: os.umask(umask) # XXX: CPython does _Py_RestoreSignals here. # Then setsid() based on ??? try: if gids: os.setgroups(gids) if gid: os.setregid(gid, gid) if uid: os.setreuid(uid, uid) if process_group is not None: os.setpgid(0, process_group) except OSError as e: e._failed_chuser = True raise if preexec_fn: preexec_fn() # Close all other fds, if asked for. This must be done # after preexec_fn runs. if close_fds: fds_to_keep = set(pass_fds) fds_to_keep.add(errpipe_write) self._close_fds(fds_to_keep, errpipe_write) if restore_signals: # restore the documented signals back to sig_dfl; # not all will be defined on every platform for sig in 'SIGPIPE', 'SIGXFZ', 'SIGXFSZ': sig = getattr(signal, sig, None) if sig is not None: signal.signal(sig, signal.SIG_DFL) if start_new_session: os.setsid() try: if env is None: os.execvp(executable, args) else: # Python 3.6 started testing for # bytes values in the env; it also # started encoding strs using # fsencode and using a lower-level # API that takes a list of keys # and values. We don't have access # to that API, so we go the reverse direction. env = {os.fsdecode(k) if isinstance(k, bytes) else k: os.fsdecode(v) if isinstance(v, bytes) else v for k, v in env.items()} os.execvpe(executable, args, env) except OSError as e: e._failed_exec = True raise except: exc_type, exc_value, tb = sys.exc_info() # Save the traceback and attach it to the exception object exc_lines = traceback.format_exception(exc_type, exc_value, tb) exc_value.child_traceback = ''.join(exc_lines) os.write(errpipe_write, pickle.dumps(exc_value)) finally: # Make sure that the process exits no matter what. # The return code does not matter much as it won't be # reported to the application os._exit(1) # Parent self._child_created = True if gc_was_enabled: gc.enable() finally: # be sure the FD is closed no matter what os.close(errpipe_write) # self._devnull is not always defined. devnull_fd = getattr(self, '_devnull', None) if p2cread != -1 and p2cwrite != -1 and p2cread != devnull_fd: os.close(p2cread) if c2pwrite != -1 and c2pread != -1 and c2pwrite != devnull_fd: os.close(c2pwrite) if errwrite != -1 and errread != -1 and errwrite != devnull_fd: os.close(errwrite) if devnull_fd is not None: os.close(devnull_fd) # Prevent a double close of these fds from __init__ on error. self._closed_child_pipe_fds = True # Wait for exec to fail or succeed; possibly raising exception errpipe_read = FileObject(errpipe_read, 'rb') data = errpipe_read.read() finally: try: if hasattr(errpipe_read, 'close'): errpipe_read.close() else: os.close(errpipe_read) except OSError: # Especially on PyPy, we sometimes see the above # `os.close(errpipe_read)` raise an OSError. # It's not entirely clear why, but it happens in # InterprocessSignalTests.test_main sometimes, which must mean # we have some sort of race condition. pass finally: errpipe_read = -1 if data != b"": self.wait() child_exception = pickle.loads(data) for fd in (p2cwrite, c2pread, errread): if fd is not None and fd != -1: os.close(fd) if isinstance(child_exception, OSError): child_exception.filename = executable if hasattr(child_exception, '_failed_chdir'): child_exception.filename = cwd if getattr(child_exception, '_failed_chuser', False): child_exception.filename = None > raise child_exception E OSError: [Errno 8] Exec format error: 'locust' /usr/lib/python3/dist-packages/gevent/subprocess.py:1838: OSError ________ StandaloneIntegrationTests.test_default_headless_spawn_options ________ self = def test_default_headless_spawn_options(self): with mock_locustfile() as mocked: > proc = subprocess.Popen( [ "locust", "-f", mocked.file_path, "--host", "https://test.com/", "--run-time", "1s", "--headless", "--loglevel", "DEBUG", "--exit-code-on-error", "0", # just to test --stop-timeout argument parsing, doesnt actually validate its function: "--stop-timeout", "1s", ], stdout=PIPE, stderr=PIPE, text=True, ) locust/test/test_main.py:371: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3/dist-packages/gevent/subprocess.py:808: in __init__ self._execute_child(args, executable, preexec_fn, close_fds, _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = args = ['locust', '-f', '/build/reproducible-path/locust-2.24.0/locust/test/mock_locustfile_1715256373_2278104_22273.py', '--host', 'https://test.com/', '--run-time', ...] executable = 'locust', preexec_fn = None, close_fds = True, pass_fds = () cwd = None, env = None, universal_newlines = None, startupinfo = None creationflags = 0, shell = False, p2cread = -1, p2cwrite = -1, c2pread = 11 c2pwrite = 80, errread = 81, errwrite = 82, restore_signals = True, gid = None gids = None, uid = None, umask = -1, start_new_session = False process_group = None def _execute_child(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, universal_newlines, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, restore_signals, gid, gids, uid, umask, start_new_session, process_group): """Execute program (POSIX version)""" if isinstance(args, (str, bytes)): args = [args] elif isinstance(args, PathLike): if shell: raise TypeError('path-like args is not allowed when ' 'shell is true') args = [fsencode(args)] # os.PathLike -> [str] else: args = list(args) if shell: # On Android the default shell is at '/system/bin/sh'. unix_shell = ( '/system/bin/sh' if hasattr(sys, 'getandroidapilevel') else '/bin/sh' ) args = [unix_shell, "-c"] + args if executable: args[0] = executable if executable is None: executable = args[0] self._loop.install_sigchld() # For transferring possible exec failure from child to parent # The first char specifies the exception type: 0 means # OSError, 1 means some other error. errpipe_read, errpipe_write = self.pipe_cloexec() # errpipe_write must not be in the standard io 0, 1, or 2 fd range. low_fds_to_close = [] while errpipe_write < 3: low_fds_to_close.append(errpipe_write) errpipe_write = os.dup(errpipe_write) for low_fd in low_fds_to_close: os.close(low_fd) try: try: gc_was_enabled = gc.isenabled() # Disable gc to avoid bug where gc -> file_dealloc -> # write to stderr -> hang. http://bugs.python.org/issue1336 gc.disable() try: self.pid = fork_and_watch(self._on_child, self._loop, True, fork) except: if gc_was_enabled: gc.enable() raise if self.pid == 0: # Child # In various places on the child side of things, we catch OSError # and add attributes to it that detail where in the process we failed; # like all exceptions until we have exec'd, this exception is pickled # and sent to the parent to raise in the calling process. # The parent uses this to decide how to treat that exception, # adjusting certain information about it as needed. # # Python 3.11.8 --- yes, a minor patch release --- stopped # letting the 'filename' parameter get set in the resulting # exception for many cases. We're not quite interpreting this # the same way the stdlib is, I'm sure, but this makes the stdlib # tests pass. # XXX: Technically we're doing a lot of stuff here that # may not be safe to do before a exec(), depending on the OS. # CPython 3 goes to great lengths to precompute a lot # of this info before the fork and pass it all to C functions that # try hard not to call things like malloc(). (Of course, # CPython 2 pretty much did what we're doing.) try: # Close parent's pipe ends if p2cwrite != -1: os.close(p2cwrite) if c2pread != -1: os.close(c2pread) if errread != -1: os.close(errread) os.close(errpipe_read) # When duping fds, if there arises a situation # where one of the fds is either 0, 1 or 2, it # is possible that it is overwritten (#12607). if c2pwrite == 0: c2pwrite = os.dup(c2pwrite) _set_inheritable(c2pwrite, False) while errwrite in (0, 1): errwrite = os.dup(errwrite) _set_inheritable(errwrite, False) # Dup fds for child def _dup2(existing, desired): # dup2() removes the CLOEXEC flag but # we must do it ourselves if dup2() # would be a no-op (issue #10806). if existing == desired: self._set_cloexec_flag(existing, False) elif existing != -1: os.dup2(existing, desired) try: self._remove_nonblock_flag(desired) except OSError: # Ignore EBADF, it may not actually be # open yet. # Tested beginning in 3.7.0b3 test_subprocess.py pass _dup2(p2cread, 0) _dup2(c2pwrite, 1) _dup2(errwrite, 2) # Close pipe fds. Make sure we don't close the # same fd more than once, or standard fds. if not True: closed = set([None]) for fd in (p2cread, c2pwrite, errwrite): if fd not in closed and fd > 2: os.close(fd) closed.add(fd) # Python 3 (with a working set_inheritable): # We no longer manually close p2cread, # c2pwrite, and errwrite here as # _close_open_fds takes care when it is # not already non-inheritable. if cwd is not None: try: os.chdir(cwd) except OSError as e: e._failed_chdir = True raise # Python 3.9 if umask >= 0: os.umask(umask) # XXX: CPython does _Py_RestoreSignals here. # Then setsid() based on ??? try: if gids: os.setgroups(gids) if gid: os.setregid(gid, gid) if uid: os.setreuid(uid, uid) if process_group is not None: os.setpgid(0, process_group) except OSError as e: e._failed_chuser = True raise if preexec_fn: preexec_fn() # Close all other fds, if asked for. This must be done # after preexec_fn runs. if close_fds: fds_to_keep = set(pass_fds) fds_to_keep.add(errpipe_write) self._close_fds(fds_to_keep, errpipe_write) if restore_signals: # restore the documented signals back to sig_dfl; # not all will be defined on every platform for sig in 'SIGPIPE', 'SIGXFZ', 'SIGXFSZ': sig = getattr(signal, sig, None) if sig is not None: signal.signal(sig, signal.SIG_DFL) if start_new_session: os.setsid() try: if env is None: os.execvp(executable, args) else: # Python 3.6 started testing for # bytes values in the env; it also # started encoding strs using # fsencode and using a lower-level # API that takes a list of keys # and values. We don't have access # to that API, so we go the reverse direction. env = {os.fsdecode(k) if isinstance(k, bytes) else k: os.fsdecode(v) if isinstance(v, bytes) else v for k, v in env.items()} os.execvpe(executable, args, env) except OSError as e: e._failed_exec = True raise except: exc_type, exc_value, tb = sys.exc_info() # Save the traceback and attach it to the exception object exc_lines = traceback.format_exception(exc_type, exc_value, tb) exc_value.child_traceback = ''.join(exc_lines) os.write(errpipe_write, pickle.dumps(exc_value)) finally: # Make sure that the process exits no matter what. # The return code does not matter much as it won't be # reported to the application os._exit(1) # Parent self._child_created = True if gc_was_enabled: gc.enable() finally: # be sure the FD is closed no matter what os.close(errpipe_write) # self._devnull is not always defined. devnull_fd = getattr(self, '_devnull', None) if p2cread != -1 and p2cwrite != -1 and p2cread != devnull_fd: os.close(p2cread) if c2pwrite != -1 and c2pread != -1 and c2pwrite != devnull_fd: os.close(c2pwrite) if errwrite != -1 and errread != -1 and errwrite != devnull_fd: os.close(errwrite) if devnull_fd is not None: os.close(devnull_fd) # Prevent a double close of these fds from __init__ on error. self._closed_child_pipe_fds = True # Wait for exec to fail or succeed; possibly raising exception errpipe_read = FileObject(errpipe_read, 'rb') data = errpipe_read.read() finally: try: if hasattr(errpipe_read, 'close'): errpipe_read.close() else: os.close(errpipe_read) except OSError: # Especially on PyPy, we sometimes see the above # `os.close(errpipe_read)` raise an OSError. # It's not entirely clear why, but it happens in # InterprocessSignalTests.test_main sometimes, which must mean # we have some sort of race condition. pass finally: errpipe_read = -1 if data != b"": self.wait() child_exception = pickle.loads(data) for fd in (p2cwrite, c2pread, errread): if fd is not None and fd != -1: os.close(fd) if isinstance(child_exception, OSError): child_exception.filename = executable if hasattr(child_exception, '_failed_chdir'): child_exception.filename = cwd if getattr(child_exception, '_failed_chuser', False): child_exception.filename = None > raise child_exception E OSError: [Errno 8] Exec format error: 'locust' /usr/lib/python3/dist-packages/gevent/subprocess.py:1838: OSError __ StandaloneIntegrationTests.test_default_headless_spawn_options_with_shape ___ self = @unittest.skipIf(sys.version_info < (3, 9), reason="dies in 3.8 on GH and I cant be bothered to investigate it") def test_default_headless_spawn_options_with_shape(self): content = MOCK_LOCUSTFILE_CONTENT + textwrap.dedent( """ class LoadTestShape(LoadTestShape): def tick(self): run_time = self.get_run_time() if run_time < 2: return (10, 1) return None """ ) with mock_locustfile(content=content) as mocked: > proc = subprocess.Popen( [ "locust", "-f", mocked.file_path, "--host", "https://test.com/", "--headless", "--exit-code-on-error", "0", ], stdout=PIPE, stderr=PIPE, text=True, ) locust/test/test_main.py:500: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3/dist-packages/gevent/subprocess.py:808: in __init__ self._execute_child(args, executable, preexec_fn, close_fds, _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = args = ['locust', '-f', '/build/reproducible-path/locust-2.24.0/locust/test/mock_locustfile_1715256373_4290316_57290.py', '--host', 'https://test.com/', '--headless', ...] executable = 'locust', preexec_fn = None, close_fds = True, pass_fds = () cwd = None, env = None, universal_newlines = None, startupinfo = None creationflags = 0, shell = False, p2cread = -1, p2cwrite = -1, c2pread = 11 c2pwrite = 80, errread = 81, errwrite = 82, restore_signals = True, gid = None gids = None, uid = None, umask = -1, start_new_session = False process_group = None def _execute_child(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, universal_newlines, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, restore_signals, gid, gids, uid, umask, start_new_session, process_group): """Execute program (POSIX version)""" if isinstance(args, (str, bytes)): args = [args] elif isinstance(args, PathLike): if shell: raise TypeError('path-like args is not allowed when ' 'shell is true') args = [fsencode(args)] # os.PathLike -> [str] else: args = list(args) if shell: # On Android the default shell is at '/system/bin/sh'. unix_shell = ( '/system/bin/sh' if hasattr(sys, 'getandroidapilevel') else '/bin/sh' ) args = [unix_shell, "-c"] + args if executable: args[0] = executable if executable is None: executable = args[0] self._loop.install_sigchld() # For transferring possible exec failure from child to parent # The first char specifies the exception type: 0 means # OSError, 1 means some other error. errpipe_read, errpipe_write = self.pipe_cloexec() # errpipe_write must not be in the standard io 0, 1, or 2 fd range. low_fds_to_close = [] while errpipe_write < 3: low_fds_to_close.append(errpipe_write) errpipe_write = os.dup(errpipe_write) for low_fd in low_fds_to_close: os.close(low_fd) try: try: gc_was_enabled = gc.isenabled() # Disable gc to avoid bug where gc -> file_dealloc -> # write to stderr -> hang. http://bugs.python.org/issue1336 gc.disable() try: self.pid = fork_and_watch(self._on_child, self._loop, True, fork) except: if gc_was_enabled: gc.enable() raise if self.pid == 0: # Child # In various places on the child side of things, we catch OSError # and add attributes to it that detail where in the process we failed; # like all exceptions until we have exec'd, this exception is pickled # and sent to the parent to raise in the calling process. # The parent uses this to decide how to treat that exception, # adjusting certain information about it as needed. # # Python 3.11.8 --- yes, a minor patch release --- stopped # letting the 'filename' parameter get set in the resulting # exception for many cases. We're not quite interpreting this # the same way the stdlib is, I'm sure, but this makes the stdlib # tests pass. # XXX: Technically we're doing a lot of stuff here that # may not be safe to do before a exec(), depending on the OS. # CPython 3 goes to great lengths to precompute a lot # of this info before the fork and pass it all to C functions that # try hard not to call things like malloc(). (Of course, # CPython 2 pretty much did what we're doing.) try: # Close parent's pipe ends if p2cwrite != -1: os.close(p2cwrite) if c2pread != -1: os.close(c2pread) if errread != -1: os.close(errread) os.close(errpipe_read) # When duping fds, if there arises a situation # where one of the fds is either 0, 1 or 2, it # is possible that it is overwritten (#12607). if c2pwrite == 0: c2pwrite = os.dup(c2pwrite) _set_inheritable(c2pwrite, False) while errwrite in (0, 1): errwrite = os.dup(errwrite) _set_inheritable(errwrite, False) # Dup fds for child def _dup2(existing, desired): # dup2() removes the CLOEXEC flag but # we must do it ourselves if dup2() # would be a no-op (issue #10806). if existing == desired: self._set_cloexec_flag(existing, False) elif existing != -1: os.dup2(existing, desired) try: self._remove_nonblock_flag(desired) except OSError: # Ignore EBADF, it may not actually be # open yet. # Tested beginning in 3.7.0b3 test_subprocess.py pass _dup2(p2cread, 0) _dup2(c2pwrite, 1) _dup2(errwrite, 2) # Close pipe fds. Make sure we don't close the # same fd more than once, or standard fds. if not True: closed = set([None]) for fd in (p2cread, c2pwrite, errwrite): if fd not in closed and fd > 2: os.close(fd) closed.add(fd) # Python 3 (with a working set_inheritable): # We no longer manually close p2cread, # c2pwrite, and errwrite here as # _close_open_fds takes care when it is # not already non-inheritable. if cwd is not None: try: os.chdir(cwd) except OSError as e: e._failed_chdir = True raise # Python 3.9 if umask >= 0: os.umask(umask) # XXX: CPython does _Py_RestoreSignals here. # Then setsid() based on ??? try: if gids: os.setgroups(gids) if gid: os.setregid(gid, gid) if uid: os.setreuid(uid, uid) if process_group is not None: os.setpgid(0, process_group) except OSError as e: e._failed_chuser = True raise if preexec_fn: preexec_fn() # Close all other fds, if asked for. This must be done # after preexec_fn runs. if close_fds: fds_to_keep = set(pass_fds) fds_to_keep.add(errpipe_write) self._close_fds(fds_to_keep, errpipe_write) if restore_signals: # restore the documented signals back to sig_dfl; # not all will be defined on every platform for sig in 'SIGPIPE', 'SIGXFZ', 'SIGXFSZ': sig = getattr(signal, sig, None) if sig is not None: signal.signal(sig, signal.SIG_DFL) if start_new_session: os.setsid() try: if env is None: os.execvp(executable, args) else: # Python 3.6 started testing for # bytes values in the env; it also # started encoding strs using # fsencode and using a lower-level # API that takes a list of keys # and values. We don't have access # to that API, so we go the reverse direction. env = {os.fsdecode(k) if isinstance(k, bytes) else k: os.fsdecode(v) if isinstance(v, bytes) else v for k, v in env.items()} os.execvpe(executable, args, env) except OSError as e: e._failed_exec = True raise except: exc_type, exc_value, tb = sys.exc_info() # Save the traceback and attach it to the exception object exc_lines = traceback.format_exception(exc_type, exc_value, tb) exc_value.child_traceback = ''.join(exc_lines) os.write(errpipe_write, pickle.dumps(exc_value)) finally: # Make sure that the process exits no matter what. # The return code does not matter much as it won't be # reported to the application os._exit(1) # Parent self._child_created = True if gc_was_enabled: gc.enable() finally: # be sure the FD is closed no matter what os.close(errpipe_write) # self._devnull is not always defined. devnull_fd = getattr(self, '_devnull', None) if p2cread != -1 and p2cwrite != -1 and p2cread != devnull_fd: os.close(p2cread) if c2pwrite != -1 and c2pread != -1 and c2pwrite != devnull_fd: os.close(c2pwrite) if errwrite != -1 and errread != -1 and errwrite != devnull_fd: os.close(errwrite) if devnull_fd is not None: os.close(devnull_fd) # Prevent a double close of these fds from __init__ on error. self._closed_child_pipe_fds = True # Wait for exec to fail or succeed; possibly raising exception errpipe_read = FileObject(errpipe_read, 'rb') data = errpipe_read.read() finally: try: if hasattr(errpipe_read, 'close'): errpipe_read.close() else: os.close(errpipe_read) except OSError: # Especially on PyPy, we sometimes see the above # `os.close(errpipe_read)` raise an OSError. # It's not entirely clear why, but it happens in # InterprocessSignalTests.test_main sometimes, which must mean # we have some sort of race condition. pass finally: errpipe_read = -1 if data != b"": self.wait() child_exception = pickle.loads(data) for fd in (p2cwrite, c2pread, errread): if fd is not None and fd != -1: os.close(fd) if isinstance(child_exception, OSError): child_exception.filename = executable if hasattr(child_exception, '_failed_chdir'): child_exception.filename = cwd if getattr(child_exception, '_failed_chuser', False): child_exception.filename = None > raise child_exception E OSError: [Errno 8] Exec format error: 'locust' /usr/lib/python3/dist-packages/gevent/subprocess.py:1838: OSError ____ StandaloneIntegrationTests.test_error_when_duplicate_shape_class_names ____ self = def test_error_when_duplicate_shape_class_names(self): MOCK_LOCUSTFILE_CONTENT_C = MOCK_LOCUSTFILE_CONTENT_A + textwrap.dedent( """ from locust import LoadTestShape class TestShape(LoadTestShape): def tick(self): run_time = self.get_run_time() if run_time < 2: return (10, 1) return None """ ) MOCK_LOCUSTFILE_CONTENT_D = MOCK_LOCUSTFILE_CONTENT_B + textwrap.dedent( """ from locust import LoadTestShape class TestShape(LoadTestShape): def tick(self): run_time = self.get_run_time() if run_time < 2: return (10, 1) return None """ ) with temporary_file(content=MOCK_LOCUSTFILE_CONTENT_C) as file1: with temporary_file(content=MOCK_LOCUSTFILE_CONTENT_D) as file2: > proc = subprocess.Popen(["locust", "-f", f"{file1},{file2}"], stdout=PIPE, stderr=PIPE, text=True) locust/test/test_main.py:1209: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3/dist-packages/gevent/subprocess.py:808: in __init__ self._execute_child(args, executable, preexec_fn, close_fds, _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = args = ['locust', '-f', '/tmp/tmptzg285h9_locustfile.py,/tmp/tmpqt17k9_m_locustfile.py'] executable = 'locust', preexec_fn = None, close_fds = True, pass_fds = () cwd = None, env = None, universal_newlines = None, startupinfo = None creationflags = 0, shell = False, p2cread = -1, p2cwrite = -1, c2pread = 11 c2pwrite = 80, errread = 81, errwrite = 82, restore_signals = True, gid = None gids = None, uid = None, umask = -1, start_new_session = False process_group = None def _execute_child(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, universal_newlines, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, restore_signals, gid, gids, uid, umask, start_new_session, process_group): """Execute program (POSIX version)""" if isinstance(args, (str, bytes)): args = [args] elif isinstance(args, PathLike): if shell: raise TypeError('path-like args is not allowed when ' 'shell is true') args = [fsencode(args)] # os.PathLike -> [str] else: args = list(args) if shell: # On Android the default shell is at '/system/bin/sh'. unix_shell = ( '/system/bin/sh' if hasattr(sys, 'getandroidapilevel') else '/bin/sh' ) args = [unix_shell, "-c"] + args if executable: args[0] = executable if executable is None: executable = args[0] self._loop.install_sigchld() # For transferring possible exec failure from child to parent # The first char specifies the exception type: 0 means # OSError, 1 means some other error. errpipe_read, errpipe_write = self.pipe_cloexec() # errpipe_write must not be in the standard io 0, 1, or 2 fd range. low_fds_to_close = [] while errpipe_write < 3: low_fds_to_close.append(errpipe_write) errpipe_write = os.dup(errpipe_write) for low_fd in low_fds_to_close: os.close(low_fd) try: try: gc_was_enabled = gc.isenabled() # Disable gc to avoid bug where gc -> file_dealloc -> # write to stderr -> hang. http://bugs.python.org/issue1336 gc.disable() try: self.pid = fork_and_watch(self._on_child, self._loop, True, fork) except: if gc_was_enabled: gc.enable() raise if self.pid == 0: # Child # In various places on the child side of things, we catch OSError # and add attributes to it that detail where in the process we failed; # like all exceptions until we have exec'd, this exception is pickled # and sent to the parent to raise in the calling process. # The parent uses this to decide how to treat that exception, # adjusting certain information about it as needed. # # Python 3.11.8 --- yes, a minor patch release --- stopped # letting the 'filename' parameter get set in the resulting # exception for many cases. We're not quite interpreting this # the same way the stdlib is, I'm sure, but this makes the stdlib # tests pass. # XXX: Technically we're doing a lot of stuff here that # may not be safe to do before a exec(), depending on the OS. # CPython 3 goes to great lengths to precompute a lot # of this info before the fork and pass it all to C functions that # try hard not to call things like malloc(). (Of course, # CPython 2 pretty much did what we're doing.) try: # Close parent's pipe ends if p2cwrite != -1: os.close(p2cwrite) if c2pread != -1: os.close(c2pread) if errread != -1: os.close(errread) os.close(errpipe_read) # When duping fds, if there arises a situation # where one of the fds is either 0, 1 or 2, it # is possible that it is overwritten (#12607). if c2pwrite == 0: c2pwrite = os.dup(c2pwrite) _set_inheritable(c2pwrite, False) while errwrite in (0, 1): errwrite = os.dup(errwrite) _set_inheritable(errwrite, False) # Dup fds for child def _dup2(existing, desired): # dup2() removes the CLOEXEC flag but # we must do it ourselves if dup2() # would be a no-op (issue #10806). if existing == desired: self._set_cloexec_flag(existing, False) elif existing != -1: os.dup2(existing, desired) try: self._remove_nonblock_flag(desired) except OSError: # Ignore EBADF, it may not actually be # open yet. # Tested beginning in 3.7.0b3 test_subprocess.py pass _dup2(p2cread, 0) _dup2(c2pwrite, 1) _dup2(errwrite, 2) # Close pipe fds. Make sure we don't close the # same fd more than once, or standard fds. if not True: closed = set([None]) for fd in (p2cread, c2pwrite, errwrite): if fd not in closed and fd > 2: os.close(fd) closed.add(fd) # Python 3 (with a working set_inheritable): # We no longer manually close p2cread, # c2pwrite, and errwrite here as # _close_open_fds takes care when it is # not already non-inheritable. if cwd is not None: try: os.chdir(cwd) except OSError as e: e._failed_chdir = True raise # Python 3.9 if umask >= 0: os.umask(umask) # XXX: CPython does _Py_RestoreSignals here. # Then setsid() based on ??? try: if gids: os.setgroups(gids) if gid: os.setregid(gid, gid) if uid: os.setreuid(uid, uid) if process_group is not None: os.setpgid(0, process_group) except OSError as e: e._failed_chuser = True raise if preexec_fn: preexec_fn() # Close all other fds, if asked for. This must be done # after preexec_fn runs. if close_fds: fds_to_keep = set(pass_fds) fds_to_keep.add(errpipe_write) self._close_fds(fds_to_keep, errpipe_write) if restore_signals: # restore the documented signals back to sig_dfl; # not all will be defined on every platform for sig in 'SIGPIPE', 'SIGXFZ', 'SIGXFSZ': sig = getattr(signal, sig, None) if sig is not None: signal.signal(sig, signal.SIG_DFL) if start_new_session: os.setsid() try: if env is None: os.execvp(executable, args) else: # Python 3.6 started testing for # bytes values in the env; it also # started encoding strs using # fsencode and using a lower-level # API that takes a list of keys # and values. We don't have access # to that API, so we go the reverse direction. env = {os.fsdecode(k) if isinstance(k, bytes) else k: os.fsdecode(v) if isinstance(v, bytes) else v for k, v in env.items()} os.execvpe(executable, args, env) except OSError as e: e._failed_exec = True raise except: exc_type, exc_value, tb = sys.exc_info() # Save the traceback and attach it to the exception object exc_lines = traceback.format_exception(exc_type, exc_value, tb) exc_value.child_traceback = ''.join(exc_lines) os.write(errpipe_write, pickle.dumps(exc_value)) finally: # Make sure that the process exits no matter what. # The return code does not matter much as it won't be # reported to the application os._exit(1) # Parent self._child_created = True if gc_was_enabled: gc.enable() finally: # be sure the FD is closed no matter what os.close(errpipe_write) # self._devnull is not always defined. devnull_fd = getattr(self, '_devnull', None) if p2cread != -1 and p2cwrite != -1 and p2cread != devnull_fd: os.close(p2cread) if c2pwrite != -1 and c2pread != -1 and c2pwrite != devnull_fd: os.close(c2pwrite) if errwrite != -1 and errread != -1 and errwrite != devnull_fd: os.close(errwrite) if devnull_fd is not None: os.close(devnull_fd) # Prevent a double close of these fds from __init__ on error. self._closed_child_pipe_fds = True # Wait for exec to fail or succeed; possibly raising exception errpipe_read = FileObject(errpipe_read, 'rb') data = errpipe_read.read() finally: try: if hasattr(errpipe_read, 'close'): errpipe_read.close() else: os.close(errpipe_read) except OSError: # Especially on PyPy, we sometimes see the above # `os.close(errpipe_read)` raise an OSError. # It's not entirely clear why, but it happens in # InterprocessSignalTests.test_main sometimes, which must mean # we have some sort of race condition. pass finally: errpipe_read = -1 if data != b"": self.wait() child_exception = pickle.loads(data) for fd in (p2cwrite, c2pread, errread): if fd is not None and fd != -1: os.close(fd) if isinstance(child_exception, OSError): child_exception.filename = executable if hasattr(child_exception, '_failed_chdir'): child_exception.filename = cwd if getattr(child_exception, '_failed_chuser', False): child_exception.filename = None > raise child_exception E OSError: [Errno 8] Exec format error: 'locust' /usr/lib/python3/dist-packages/gevent/subprocess.py:1838: OSError _____ StandaloneIntegrationTests.test_error_when_duplicate_userclass_names _____ self = def test_error_when_duplicate_userclass_names(self): MOCK_LOCUSTFILE_CONTENT_C = textwrap.dedent( """ from locust import User, task, constant, events class TestUser1(User): wait_time = constant(3) @task def my_task(self): print("running my_task()") """ ) with temporary_file(content=MOCK_LOCUSTFILE_CONTENT_A) as file1: with temporary_file(content=MOCK_LOCUSTFILE_CONTENT_C) as file2: > proc = subprocess.Popen(["locust", "-f", f"{file1},{file2}"], stdout=PIPE, stderr=PIPE, text=True) locust/test/test_main.py:1157: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3/dist-packages/gevent/subprocess.py:808: in __init__ self._execute_child(args, executable, preexec_fn, close_fds, _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = args = ['locust', '-f', '/tmp/tmptv_euztw_locustfile.py,/tmp/tmpluczeuic_locustfile.py'] executable = 'locust', preexec_fn = None, close_fds = True, pass_fds = () cwd = None, env = None, universal_newlines = None, startupinfo = None creationflags = 0, shell = False, p2cread = -1, p2cwrite = -1, c2pread = 11 c2pwrite = 80, errread = 81, errwrite = 82, restore_signals = True, gid = None gids = None, uid = None, umask = -1, start_new_session = False process_group = None def _execute_child(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, universal_newlines, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, restore_signals, gid, gids, uid, umask, start_new_session, process_group): """Execute program (POSIX version)""" if isinstance(args, (str, bytes)): args = [args] elif isinstance(args, PathLike): if shell: raise TypeError('path-like args is not allowed when ' 'shell is true') args = [fsencode(args)] # os.PathLike -> [str] else: args = list(args) if shell: # On Android the default shell is at '/system/bin/sh'. unix_shell = ( '/system/bin/sh' if hasattr(sys, 'getandroidapilevel') else '/bin/sh' ) args = [unix_shell, "-c"] + args if executable: args[0] = executable if executable is None: executable = args[0] self._loop.install_sigchld() # For transferring possible exec failure from child to parent # The first char specifies the exception type: 0 means # OSError, 1 means some other error. errpipe_read, errpipe_write = self.pipe_cloexec() # errpipe_write must not be in the standard io 0, 1, or 2 fd range. low_fds_to_close = [] while errpipe_write < 3: low_fds_to_close.append(errpipe_write) errpipe_write = os.dup(errpipe_write) for low_fd in low_fds_to_close: os.close(low_fd) try: try: gc_was_enabled = gc.isenabled() # Disable gc to avoid bug where gc -> file_dealloc -> # write to stderr -> hang. http://bugs.python.org/issue1336 gc.disable() try: self.pid = fork_and_watch(self._on_child, self._loop, True, fork) except: if gc_was_enabled: gc.enable() raise if self.pid == 0: # Child # In various places on the child side of things, we catch OSError # and add attributes to it that detail where in the process we failed; # like all exceptions until we have exec'd, this exception is pickled # and sent to the parent to raise in the calling process. # The parent uses this to decide how to treat that exception, # adjusting certain information about it as needed. # # Python 3.11.8 --- yes, a minor patch release --- stopped # letting the 'filename' parameter get set in the resulting # exception for many cases. We're not quite interpreting this # the same way the stdlib is, I'm sure, but this makes the stdlib # tests pass. # XXX: Technically we're doing a lot of stuff here that # may not be safe to do before a exec(), depending on the OS. # CPython 3 goes to great lengths to precompute a lot # of this info before the fork and pass it all to C functions that # try hard not to call things like malloc(). (Of course, # CPython 2 pretty much did what we're doing.) try: # Close parent's pipe ends if p2cwrite != -1: os.close(p2cwrite) if c2pread != -1: os.close(c2pread) if errread != -1: os.close(errread) os.close(errpipe_read) # When duping fds, if there arises a situation # where one of the fds is either 0, 1 or 2, it # is possible that it is overwritten (#12607). if c2pwrite == 0: c2pwrite = os.dup(c2pwrite) _set_inheritable(c2pwrite, False) while errwrite in (0, 1): errwrite = os.dup(errwrite) _set_inheritable(errwrite, False) # Dup fds for child def _dup2(existing, desired): # dup2() removes the CLOEXEC flag but # we must do it ourselves if dup2() # would be a no-op (issue #10806). if existing == desired: self._set_cloexec_flag(existing, False) elif existing != -1: os.dup2(existing, desired) try: self._remove_nonblock_flag(desired) except OSError: # Ignore EBADF, it may not actually be # open yet. # Tested beginning in 3.7.0b3 test_subprocess.py pass _dup2(p2cread, 0) _dup2(c2pwrite, 1) _dup2(errwrite, 2) # Close pipe fds. Make sure we don't close the # same fd more than once, or standard fds. if not True: closed = set([None]) for fd in (p2cread, c2pwrite, errwrite): if fd not in closed and fd > 2: os.close(fd) closed.add(fd) # Python 3 (with a working set_inheritable): # We no longer manually close p2cread, # c2pwrite, and errwrite here as # _close_open_fds takes care when it is # not already non-inheritable. if cwd is not None: try: os.chdir(cwd) except OSError as e: e._failed_chdir = True raise # Python 3.9 if umask >= 0: os.umask(umask) # XXX: CPython does _Py_RestoreSignals here. # Then setsid() based on ??? try: if gids: os.setgroups(gids) if gid: os.setregid(gid, gid) if uid: os.setreuid(uid, uid) if process_group is not None: os.setpgid(0, process_group) except OSError as e: e._failed_chuser = True raise if preexec_fn: preexec_fn() # Close all other fds, if asked for. This must be done # after preexec_fn runs. if close_fds: fds_to_keep = set(pass_fds) fds_to_keep.add(errpipe_write) self._close_fds(fds_to_keep, errpipe_write) if restore_signals: # restore the documented signals back to sig_dfl; # not all will be defined on every platform for sig in 'SIGPIPE', 'SIGXFZ', 'SIGXFSZ': sig = getattr(signal, sig, None) if sig is not None: signal.signal(sig, signal.SIG_DFL) if start_new_session: os.setsid() try: if env is None: os.execvp(executable, args) else: # Python 3.6 started testing for # bytes values in the env; it also # started encoding strs using # fsencode and using a lower-level # API that takes a list of keys # and values. We don't have access # to that API, so we go the reverse direction. env = {os.fsdecode(k) if isinstance(k, bytes) else k: os.fsdecode(v) if isinstance(v, bytes) else v for k, v in env.items()} os.execvpe(executable, args, env) except OSError as e: e._failed_exec = True raise except: exc_type, exc_value, tb = sys.exc_info() # Save the traceback and attach it to the exception object exc_lines = traceback.format_exception(exc_type, exc_value, tb) exc_value.child_traceback = ''.join(exc_lines) os.write(errpipe_write, pickle.dumps(exc_value)) finally: # Make sure that the process exits no matter what. # The return code does not matter much as it won't be # reported to the application os._exit(1) # Parent self._child_created = True if gc_was_enabled: gc.enable() finally: # be sure the FD is closed no matter what os.close(errpipe_write) # self._devnull is not always defined. devnull_fd = getattr(self, '_devnull', None) if p2cread != -1 and p2cwrite != -1 and p2cread != devnull_fd: os.close(p2cread) if c2pwrite != -1 and c2pread != -1 and c2pwrite != devnull_fd: os.close(c2pwrite) if errwrite != -1 and errread != -1 and errwrite != devnull_fd: os.close(errwrite) if devnull_fd is not None: os.close(devnull_fd) # Prevent a double close of these fds from __init__ on error. self._closed_child_pipe_fds = True # Wait for exec to fail or succeed; possibly raising exception errpipe_read = FileObject(errpipe_read, 'rb') data = errpipe_read.read() finally: try: if hasattr(errpipe_read, 'close'): errpipe_read.close() else: os.close(errpipe_read) except OSError: # Especially on PyPy, we sometimes see the above # `os.close(errpipe_read)` raise an OSError. # It's not entirely clear why, but it happens in # InterprocessSignalTests.test_main sometimes, which must mean # we have some sort of race condition. pass finally: errpipe_read = -1 if data != b"": self.wait() child_exception = pickle.loads(data) for fd in (p2cwrite, c2pread, errread): if fd is not None and fd != -1: os.close(fd) if isinstance(child_exception, OSError): child_exception.filename = executable if hasattr(child_exception, '_failed_chdir'): child_exception.filename = cwd if getattr(child_exception, '_failed_chuser', False): child_exception.filename = None > raise child_exception E OSError: [Errno 8] Exec format error: 'locust' /usr/lib/python3/dist-packages/gevent/subprocess.py:1838: OSError __ StandaloneIntegrationTests.test_error_when_locustfiles_directory_is_empty ___ self = def test_error_when_locustfiles_directory_is_empty(self): with TemporaryDirectory() as temp_dir: > proc = subprocess.Popen(["locust", "-f", temp_dir], stdout=PIPE, stderr=PIPE, text=True) locust/test/test_main.py:1298: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3/dist-packages/gevent/subprocess.py:808: in __init__ self._execute_child(args, executable, preexec_fn, close_fds, _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = args = ['locust', '-f', '/tmp/tmp4lji35lh'], executable = 'locust' preexec_fn = None, close_fds = True, pass_fds = (), cwd = None, env = None universal_newlines = None, startupinfo = None, creationflags = 0, shell = False p2cread = -1, p2cwrite = -1, c2pread = 11, c2pwrite = 80, errread = 81 errwrite = 82, restore_signals = True, gid = None, gids = None, uid = None umask = -1, start_new_session = False, process_group = None def _execute_child(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, universal_newlines, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, restore_signals, gid, gids, uid, umask, start_new_session, process_group): """Execute program (POSIX version)""" if isinstance(args, (str, bytes)): args = [args] elif isinstance(args, PathLike): if shell: raise TypeError('path-like args is not allowed when ' 'shell is true') args = [fsencode(args)] # os.PathLike -> [str] else: args = list(args) if shell: # On Android the default shell is at '/system/bin/sh'. unix_shell = ( '/system/bin/sh' if hasattr(sys, 'getandroidapilevel') else '/bin/sh' ) args = [unix_shell, "-c"] + args if executable: args[0] = executable if executable is None: executable = args[0] self._loop.install_sigchld() # For transferring possible exec failure from child to parent # The first char specifies the exception type: 0 means # OSError, 1 means some other error. errpipe_read, errpipe_write = self.pipe_cloexec() # errpipe_write must not be in the standard io 0, 1, or 2 fd range. low_fds_to_close = [] while errpipe_write < 3: low_fds_to_close.append(errpipe_write) errpipe_write = os.dup(errpipe_write) for low_fd in low_fds_to_close: os.close(low_fd) try: try: gc_was_enabled = gc.isenabled() # Disable gc to avoid bug where gc -> file_dealloc -> # write to stderr -> hang. http://bugs.python.org/issue1336 gc.disable() try: self.pid = fork_and_watch(self._on_child, self._loop, True, fork) except: if gc_was_enabled: gc.enable() raise if self.pid == 0: # Child # In various places on the child side of things, we catch OSError # and add attributes to it that detail where in the process we failed; # like all exceptions until we have exec'd, this exception is pickled # and sent to the parent to raise in the calling process. # The parent uses this to decide how to treat that exception, # adjusting certain information about it as needed. # # Python 3.11.8 --- yes, a minor patch release --- stopped # letting the 'filename' parameter get set in the resulting # exception for many cases. We're not quite interpreting this # the same way the stdlib is, I'm sure, but this makes the stdlib # tests pass. # XXX: Technically we're doing a lot of stuff here that # may not be safe to do before a exec(), depending on the OS. # CPython 3 goes to great lengths to precompute a lot # of this info before the fork and pass it all to C functions that # try hard not to call things like malloc(). (Of course, # CPython 2 pretty much did what we're doing.) try: # Close parent's pipe ends if p2cwrite != -1: os.close(p2cwrite) if c2pread != -1: os.close(c2pread) if errread != -1: os.close(errread) os.close(errpipe_read) # When duping fds, if there arises a situation # where one of the fds is either 0, 1 or 2, it # is possible that it is overwritten (#12607). if c2pwrite == 0: c2pwrite = os.dup(c2pwrite) _set_inheritable(c2pwrite, False) while errwrite in (0, 1): errwrite = os.dup(errwrite) _set_inheritable(errwrite, False) # Dup fds for child def _dup2(existing, desired): # dup2() removes the CLOEXEC flag but # we must do it ourselves if dup2() # would be a no-op (issue #10806). if existing == desired: self._set_cloexec_flag(existing, False) elif existing != -1: os.dup2(existing, desired) try: self._remove_nonblock_flag(desired) except OSError: # Ignore EBADF, it may not actually be # open yet. # Tested beginning in 3.7.0b3 test_subprocess.py pass _dup2(p2cread, 0) _dup2(c2pwrite, 1) _dup2(errwrite, 2) # Close pipe fds. Make sure we don't close the # same fd more than once, or standard fds. if not True: closed = set([None]) for fd in (p2cread, c2pwrite, errwrite): if fd not in closed and fd > 2: os.close(fd) closed.add(fd) # Python 3 (with a working set_inheritable): # We no longer manually close p2cread, # c2pwrite, and errwrite here as # _close_open_fds takes care when it is # not already non-inheritable. if cwd is not None: try: os.chdir(cwd) except OSError as e: e._failed_chdir = True raise # Python 3.9 if umask >= 0: os.umask(umask) # XXX: CPython does _Py_RestoreSignals here. # Then setsid() based on ??? try: if gids: os.setgroups(gids) if gid: os.setregid(gid, gid) if uid: os.setreuid(uid, uid) if process_group is not None: os.setpgid(0, process_group) except OSError as e: e._failed_chuser = True raise if preexec_fn: preexec_fn() # Close all other fds, if asked for. This must be done # after preexec_fn runs. if close_fds: fds_to_keep = set(pass_fds) fds_to_keep.add(errpipe_write) self._close_fds(fds_to_keep, errpipe_write) if restore_signals: # restore the documented signals back to sig_dfl; # not all will be defined on every platform for sig in 'SIGPIPE', 'SIGXFZ', 'SIGXFSZ': sig = getattr(signal, sig, None) if sig is not None: signal.signal(sig, signal.SIG_DFL) if start_new_session: os.setsid() try: if env is None: os.execvp(executable, args) else: # Python 3.6 started testing for # bytes values in the env; it also # started encoding strs using # fsencode and using a lower-level # API that takes a list of keys # and values. We don't have access # to that API, so we go the reverse direction. env = {os.fsdecode(k) if isinstance(k, bytes) else k: os.fsdecode(v) if isinstance(v, bytes) else v for k, v in env.items()} os.execvpe(executable, args, env) except OSError as e: e._failed_exec = True raise except: exc_type, exc_value, tb = sys.exc_info() # Save the traceback and attach it to the exception object exc_lines = traceback.format_exception(exc_type, exc_value, tb) exc_value.child_traceback = ''.join(exc_lines) os.write(errpipe_write, pickle.dumps(exc_value)) finally: # Make sure that the process exits no matter what. # The return code does not matter much as it won't be # reported to the application os._exit(1) # Parent self._child_created = True if gc_was_enabled: gc.enable() finally: # be sure the FD is closed no matter what os.close(errpipe_write) # self._devnull is not always defined. devnull_fd = getattr(self, '_devnull', None) if p2cread != -1 and p2cwrite != -1 and p2cread != devnull_fd: os.close(p2cread) if c2pwrite != -1 and c2pread != -1 and c2pwrite != devnull_fd: os.close(c2pwrite) if errwrite != -1 and errread != -1 and errwrite != devnull_fd: os.close(errwrite) if devnull_fd is not None: os.close(devnull_fd) # Prevent a double close of these fds from __init__ on error. self._closed_child_pipe_fds = True # Wait for exec to fail or succeed; possibly raising exception errpipe_read = FileObject(errpipe_read, 'rb') data = errpipe_read.read() finally: try: if hasattr(errpipe_read, 'close'): errpipe_read.close() else: os.close(errpipe_read) except OSError: # Especially on PyPy, we sometimes see the above # `os.close(errpipe_read)` raise an OSError. # It's not entirely clear why, but it happens in # InterprocessSignalTests.test_main sometimes, which must mean # we have some sort of race condition. pass finally: errpipe_read = -1 if data != b"": self.wait() child_exception = pickle.loads(data) for fd in (p2cwrite, c2pread, errread): if fd is not None and fd != -1: os.close(fd) if isinstance(child_exception, OSError): child_exception.filename = executable if hasattr(child_exception, '_failed_chdir'): child_exception.filename = cwd if getattr(child_exception, '_failed_chuser', False): child_exception.filename = None > raise child_exception E OSError: [Errno 8] Exec format error: 'locust' /usr/lib/python3/dist-packages/gevent/subprocess.py:1838: OSError ________ StandaloneIntegrationTests.test_error_when_no_tasks_match_tags ________ self = def test_error_when_no_tasks_match_tags(self): content = """ from locust import HttpUser, TaskSet, task, constant, LoadTestShape, tag class MyUser(HttpUser): host = "http://127.0.0.1:8089" wait_time = constant(1) @tag("tag1") @task def task1(self): print("task1") """ with mock_locustfile(content=content) as mocked: > proc = subprocess.Popen( [ "locust", "-f", mocked.file_path, "--headless", "-t", "1", "--tags", "tag2", ], stdout=PIPE, stderr=PIPE, text=True, ) locust/test/test_main.py:1317: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3/dist-packages/gevent/subprocess.py:808: in __init__ self._execute_child(args, executable, preexec_fn, close_fds, _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = args = ['locust', '-f', '/build/reproducible-path/locust-2.24.0/locust/test/mock_locustfile_1715256374_387504_33769.py', '--headless', '-t', '1', ...] executable = 'locust', preexec_fn = None, close_fds = True, pass_fds = () cwd = None, env = None, universal_newlines = None, startupinfo = None creationflags = 0, shell = False, p2cread = -1, p2cwrite = -1, c2pread = 11 c2pwrite = 80, errread = 81, errwrite = 82, restore_signals = True, gid = None gids = None, uid = None, umask = -1, start_new_session = False process_group = None def _execute_child(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, universal_newlines, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, restore_signals, gid, gids, uid, umask, start_new_session, process_group): """Execute program (POSIX version)""" if isinstance(args, (str, bytes)): args = [args] elif isinstance(args, PathLike): if shell: raise TypeError('path-like args is not allowed when ' 'shell is true') args = [fsencode(args)] # os.PathLike -> [str] else: args = list(args) if shell: # On Android the default shell is at '/system/bin/sh'. unix_shell = ( '/system/bin/sh' if hasattr(sys, 'getandroidapilevel') else '/bin/sh' ) args = [unix_shell, "-c"] + args if executable: args[0] = executable if executable is None: executable = args[0] self._loop.install_sigchld() # For transferring possible exec failure from child to parent # The first char specifies the exception type: 0 means # OSError, 1 means some other error. errpipe_read, errpipe_write = self.pipe_cloexec() # errpipe_write must not be in the standard io 0, 1, or 2 fd range. low_fds_to_close = [] while errpipe_write < 3: low_fds_to_close.append(errpipe_write) errpipe_write = os.dup(errpipe_write) for low_fd in low_fds_to_close: os.close(low_fd) try: try: gc_was_enabled = gc.isenabled() # Disable gc to avoid bug where gc -> file_dealloc -> # write to stderr -> hang. http://bugs.python.org/issue1336 gc.disable() try: self.pid = fork_and_watch(self._on_child, self._loop, True, fork) except: if gc_was_enabled: gc.enable() raise if self.pid == 0: # Child # In various places on the child side of things, we catch OSError # and add attributes to it that detail where in the process we failed; # like all exceptions until we have exec'd, this exception is pickled # and sent to the parent to raise in the calling process. # The parent uses this to decide how to treat that exception, # adjusting certain information about it as needed. # # Python 3.11.8 --- yes, a minor patch release --- stopped # letting the 'filename' parameter get set in the resulting # exception for many cases. We're not quite interpreting this # the same way the stdlib is, I'm sure, but this makes the stdlib # tests pass. # XXX: Technically we're doing a lot of stuff here that # may not be safe to do before a exec(), depending on the OS. # CPython 3 goes to great lengths to precompute a lot # of this info before the fork and pass it all to C functions that # try hard not to call things like malloc(). (Of course, # CPython 2 pretty much did what we're doing.) try: # Close parent's pipe ends if p2cwrite != -1: os.close(p2cwrite) if c2pread != -1: os.close(c2pread) if errread != -1: os.close(errread) os.close(errpipe_read) # When duping fds, if there arises a situation # where one of the fds is either 0, 1 or 2, it # is possible that it is overwritten (#12607). if c2pwrite == 0: c2pwrite = os.dup(c2pwrite) _set_inheritable(c2pwrite, False) while errwrite in (0, 1): errwrite = os.dup(errwrite) _set_inheritable(errwrite, False) # Dup fds for child def _dup2(existing, desired): # dup2() removes the CLOEXEC flag but # we must do it ourselves if dup2() # would be a no-op (issue #10806). if existing == desired: self._set_cloexec_flag(existing, False) elif existing != -1: os.dup2(existing, desired) try: self._remove_nonblock_flag(desired) except OSError: # Ignore EBADF, it may not actually be # open yet. # Tested beginning in 3.7.0b3 test_subprocess.py pass _dup2(p2cread, 0) _dup2(c2pwrite, 1) _dup2(errwrite, 2) # Close pipe fds. Make sure we don't close the # same fd more than once, or standard fds. if not True: closed = set([None]) for fd in (p2cread, c2pwrite, errwrite): if fd not in closed and fd > 2: os.close(fd) closed.add(fd) # Python 3 (with a working set_inheritable): # We no longer manually close p2cread, # c2pwrite, and errwrite here as # _close_open_fds takes care when it is # not already non-inheritable. if cwd is not None: try: os.chdir(cwd) except OSError as e: e._failed_chdir = True raise # Python 3.9 if umask >= 0: os.umask(umask) # XXX: CPython does _Py_RestoreSignals here. # Then setsid() based on ??? try: if gids: os.setgroups(gids) if gid: os.setregid(gid, gid) if uid: os.setreuid(uid, uid) if process_group is not None: os.setpgid(0, process_group) except OSError as e: e._failed_chuser = True raise if preexec_fn: preexec_fn() # Close all other fds, if asked for. This must be done # after preexec_fn runs. if close_fds: fds_to_keep = set(pass_fds) fds_to_keep.add(errpipe_write) self._close_fds(fds_to_keep, errpipe_write) if restore_signals: # restore the documented signals back to sig_dfl; # not all will be defined on every platform for sig in 'SIGPIPE', 'SIGXFZ', 'SIGXFSZ': sig = getattr(signal, sig, None) if sig is not None: signal.signal(sig, signal.SIG_DFL) if start_new_session: os.setsid() try: if env is None: os.execvp(executable, args) else: # Python 3.6 started testing for # bytes values in the env; it also # started encoding strs using # fsencode and using a lower-level # API that takes a list of keys # and values. We don't have access # to that API, so we go the reverse direction. env = {os.fsdecode(k) if isinstance(k, bytes) else k: os.fsdecode(v) if isinstance(v, bytes) else v for k, v in env.items()} os.execvpe(executable, args, env) except OSError as e: e._failed_exec = True raise except: exc_type, exc_value, tb = sys.exc_info() # Save the traceback and attach it to the exception object exc_lines = traceback.format_exception(exc_type, exc_value, tb) exc_value.child_traceback = ''.join(exc_lines) os.write(errpipe_write, pickle.dumps(exc_value)) finally: # Make sure that the process exits no matter what. # The return code does not matter much as it won't be # reported to the application os._exit(1) # Parent self._child_created = True if gc_was_enabled: gc.enable() finally: # be sure the FD is closed no matter what os.close(errpipe_write) # self._devnull is not always defined. devnull_fd = getattr(self, '_devnull', None) if p2cread != -1 and p2cwrite != -1 and p2cread != devnull_fd: os.close(p2cread) if c2pwrite != -1 and c2pread != -1 and c2pwrite != devnull_fd: os.close(c2pwrite) if errwrite != -1 and errread != -1 and errwrite != devnull_fd: os.close(errwrite) if devnull_fd is not None: os.close(devnull_fd) # Prevent a double close of these fds from __init__ on error. self._closed_child_pipe_fds = True # Wait for exec to fail or succeed; possibly raising exception errpipe_read = FileObject(errpipe_read, 'rb') data = errpipe_read.read() finally: try: if hasattr(errpipe_read, 'close'): errpipe_read.close() else: os.close(errpipe_read) except OSError: # Especially on PyPy, we sometimes see the above # `os.close(errpipe_read)` raise an OSError. # It's not entirely clear why, but it happens in # InterprocessSignalTests.test_main sometimes, which must mean # we have some sort of race condition. pass finally: errpipe_read = -1 if data != b"": self.wait() child_exception = pickle.loads(data) for fd in (p2cwrite, c2pread, errread): if fd is not None and fd != -1: os.close(fd) if isinstance(child_exception, OSError): child_exception.filename = executable if hasattr(child_exception, '_failed_chdir'): child_exception.filename = cwd if getattr(child_exception, '_failed_chuser', False): child_exception.filename = None > raise child_exception E OSError: [Errno 8] Exec format error: 'locust' /usr/lib/python3/dist-packages/gevent/subprocess.py:1838: OSError _ StandaloneIntegrationTests.test_error_when_providing_both_run_time_and_a_shape_class _ self = def test_error_when_providing_both_run_time_and_a_shape_class(self): content = MOCK_LOCUSTFILE_CONTENT + textwrap.dedent( """ from locust import LoadTestShape class TestShape(LoadTestShape): def tick(self): return None """ ) with mock_locustfile(content=content) as mocked: > out = self.assert_run( [ "locust", "-f", mocked.file_path, "--run-time=1s", "--headless", "--exit-code-on-error", "0", ] ) locust/test/test_main.py:1226: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ locust/test/test_main.py:65: in assert_run out = subprocess.run(cmd, capture_output=True, text=True, timeout=timeout) /usr/lib/python3/dist-packages/gevent/subprocess.py:2001: in run with Popen(*popenargs, **kwargs) as process: /usr/lib/python3/dist-packages/gevent/subprocess.py:808: in __init__ self._execute_child(args, executable, preexec_fn, close_fds, _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = args = ['locust', '-f', '/build/reproducible-path/locust-2.24.0/locust/test/mock_locustfile_1715256374_7632844_87947.py', '--run-time=1s', '--headless', '--exit-code-on-error', ...] executable = 'locust', preexec_fn = None, close_fds = True, pass_fds = () cwd = None, env = None, universal_newlines = None, startupinfo = None creationflags = 0, shell = False, p2cread = -1, p2cwrite = -1, c2pread = 11 c2pwrite = 80, errread = 81, errwrite = 82, restore_signals = True, gid = None gids = None, uid = None, umask = -1, start_new_session = False process_group = None def _execute_child(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, universal_newlines, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, restore_signals, gid, gids, uid, umask, start_new_session, process_group): """Execute program (POSIX version)""" if isinstance(args, (str, bytes)): args = [args] elif isinstance(args, PathLike): if shell: raise TypeError('path-like args is not allowed when ' 'shell is true') args = [fsencode(args)] # os.PathLike -> [str] else: args = list(args) if shell: # On Android the default shell is at '/system/bin/sh'. unix_shell = ( '/system/bin/sh' if hasattr(sys, 'getandroidapilevel') else '/bin/sh' ) args = [unix_shell, "-c"] + args if executable: args[0] = executable if executable is None: executable = args[0] self._loop.install_sigchld() # For transferring possible exec failure from child to parent # The first char specifies the exception type: 0 means # OSError, 1 means some other error. errpipe_read, errpipe_write = self.pipe_cloexec() # errpipe_write must not be in the standard io 0, 1, or 2 fd range. low_fds_to_close = [] while errpipe_write < 3: low_fds_to_close.append(errpipe_write) errpipe_write = os.dup(errpipe_write) for low_fd in low_fds_to_close: os.close(low_fd) try: try: gc_was_enabled = gc.isenabled() # Disable gc to avoid bug where gc -> file_dealloc -> # write to stderr -> hang. http://bugs.python.org/issue1336 gc.disable() try: self.pid = fork_and_watch(self._on_child, self._loop, True, fork) except: if gc_was_enabled: gc.enable() raise if self.pid == 0: # Child # In various places on the child side of things, we catch OSError # and add attributes to it that detail where in the process we failed; # like all exceptions until we have exec'd, this exception is pickled # and sent to the parent to raise in the calling process. # The parent uses this to decide how to treat that exception, # adjusting certain information about it as needed. # # Python 3.11.8 --- yes, a minor patch release --- stopped # letting the 'filename' parameter get set in the resulting # exception for many cases. We're not quite interpreting this # the same way the stdlib is, I'm sure, but this makes the stdlib # tests pass. # XXX: Technically we're doing a lot of stuff here that # may not be safe to do before a exec(), depending on the OS. # CPython 3 goes to great lengths to precompute a lot # of this info before the fork and pass it all to C functions that # try hard not to call things like malloc(). (Of course, # CPython 2 pretty much did what we're doing.) try: # Close parent's pipe ends if p2cwrite != -1: os.close(p2cwrite) if c2pread != -1: os.close(c2pread) if errread != -1: os.close(errread) os.close(errpipe_read) # When duping fds, if there arises a situation # where one of the fds is either 0, 1 or 2, it # is possible that it is overwritten (#12607). if c2pwrite == 0: c2pwrite = os.dup(c2pwrite) _set_inheritable(c2pwrite, False) while errwrite in (0, 1): errwrite = os.dup(errwrite) _set_inheritable(errwrite, False) # Dup fds for child def _dup2(existing, desired): # dup2() removes the CLOEXEC flag but # we must do it ourselves if dup2() # would be a no-op (issue #10806). if existing == desired: self._set_cloexec_flag(existing, False) elif existing != -1: os.dup2(existing, desired) try: self._remove_nonblock_flag(desired) except OSError: # Ignore EBADF, it may not actually be # open yet. # Tested beginning in 3.7.0b3 test_subprocess.py pass _dup2(p2cread, 0) _dup2(c2pwrite, 1) _dup2(errwrite, 2) # Close pipe fds. Make sure we don't close the # same fd more than once, or standard fds. if not True: closed = set([None]) for fd in (p2cread, c2pwrite, errwrite): if fd not in closed and fd > 2: os.close(fd) closed.add(fd) # Python 3 (with a working set_inheritable): # We no longer manually close p2cread, # c2pwrite, and errwrite here as # _close_open_fds takes care when it is # not already non-inheritable. if cwd is not None: try: os.chdir(cwd) except OSError as e: e._failed_chdir = True raise # Python 3.9 if umask >= 0: os.umask(umask) # XXX: CPython does _Py_RestoreSignals here. # Then setsid() based on ??? try: if gids: os.setgroups(gids) if gid: os.setregid(gid, gid) if uid: os.setreuid(uid, uid) if process_group is not None: os.setpgid(0, process_group) except OSError as e: e._failed_chuser = True raise if preexec_fn: preexec_fn() # Close all other fds, if asked for. This must be done # after preexec_fn runs. if close_fds: fds_to_keep = set(pass_fds) fds_to_keep.add(errpipe_write) self._close_fds(fds_to_keep, errpipe_write) if restore_signals: # restore the documented signals back to sig_dfl; # not all will be defined on every platform for sig in 'SIGPIPE', 'SIGXFZ', 'SIGXFSZ': sig = getattr(signal, sig, None) if sig is not None: signal.signal(sig, signal.SIG_DFL) if start_new_session: os.setsid() try: if env is None: os.execvp(executable, args) else: # Python 3.6 started testing for # bytes values in the env; it also # started encoding strs using # fsencode and using a lower-level # API that takes a list of keys # and values. We don't have access # to that API, so we go the reverse direction. env = {os.fsdecode(k) if isinstance(k, bytes) else k: os.fsdecode(v) if isinstance(v, bytes) else v for k, v in env.items()} os.execvpe(executable, args, env) except OSError as e: e._failed_exec = True raise except: exc_type, exc_value, tb = sys.exc_info() # Save the traceback and attach it to the exception object exc_lines = traceback.format_exception(exc_type, exc_value, tb) exc_value.child_traceback = ''.join(exc_lines) os.write(errpipe_write, pickle.dumps(exc_value)) finally: # Make sure that the process exits no matter what. # The return code does not matter much as it won't be # reported to the application os._exit(1) # Parent self._child_created = True if gc_was_enabled: gc.enable() finally: # be sure the FD is closed no matter what os.close(errpipe_write) # self._devnull is not always defined. devnull_fd = getattr(self, '_devnull', None) if p2cread != -1 and p2cwrite != -1 and p2cread != devnull_fd: os.close(p2cread) if c2pwrite != -1 and c2pread != -1 and c2pwrite != devnull_fd: os.close(c2pwrite) if errwrite != -1 and errread != -1 and errwrite != devnull_fd: os.close(errwrite) if devnull_fd is not None: os.close(devnull_fd) # Prevent a double close of these fds from __init__ on error. self._closed_child_pipe_fds = True # Wait for exec to fail or succeed; possibly raising exception errpipe_read = FileObject(errpipe_read, 'rb') data = errpipe_read.read() finally: try: if hasattr(errpipe_read, 'close'): errpipe_read.close() else: os.close(errpipe_read) except OSError: # Especially on PyPy, we sometimes see the above # `os.close(errpipe_read)` raise an OSError. # It's not entirely clear why, but it happens in # InterprocessSignalTests.test_main sometimes, which must mean # we have some sort of race condition. pass finally: errpipe_read = -1 if data != b"": self.wait() child_exception = pickle.loads(data) for fd in (p2cwrite, c2pread, errread): if fd is not None and fd != -1: os.close(fd) if isinstance(child_exception, OSError): child_exception.filename = executable if hasattr(child_exception, '_failed_chdir'): child_exception.filename = cwd if getattr(child_exception, '_failed_chuser', False): child_exception.filename = None > raise child_exception E OSError: [Errno 8] Exec format error: 'locust' /usr/lib/python3/dist-packages/gevent/subprocess.py:1838: OSError ____ StandaloneIntegrationTests.test_graceful_exit_when_keyboard_interrupt _____ self = @unittest.skipIf(os.name == "nt", reason="Signal handling on windows is hard") def test_graceful_exit_when_keyboard_interrupt(self): with temporary_file( content=textwrap.dedent( """ from locust import User, events, task, constant, LoadTestShape @events.test_stop.add_listener def on_test_stop(environment, **kwargs) -> None: print("Test Stopped") class LoadTestShape(LoadTestShape): def tick(self): run_time = self.get_run_time() if run_time < 2: return (10, 1) return None class TestUser(User): wait_time = constant(3) @task def my_task(self): print("running my_task()") """ ) ) as mocked: > proc = subprocess.Popen( [ "locust", "-f", mocked, "--headless", ], stdout=PIPE, stderr=PIPE, text=True, ) locust/test/test_main.py:1363: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3/dist-packages/gevent/subprocess.py:808: in __init__ self._execute_child(args, executable, preexec_fn, close_fds, _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = args = ['locust', '-f', '/tmp/tmpvgcn6lb7_locustfile.py', '--headless'] executable = 'locust', preexec_fn = None, close_fds = True, pass_fds = () cwd = None, env = None, universal_newlines = None, startupinfo = None creationflags = 0, shell = False, p2cread = -1, p2cwrite = -1, c2pread = 11 c2pwrite = 80, errread = 81, errwrite = 82, restore_signals = True, gid = None gids = None, uid = None, umask = -1, start_new_session = False process_group = None def _execute_child(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, universal_newlines, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, restore_signals, gid, gids, uid, umask, start_new_session, process_group): """Execute program (POSIX version)""" if isinstance(args, (str, bytes)): args = [args] elif isinstance(args, PathLike): if shell: raise TypeError('path-like args is not allowed when ' 'shell is true') args = [fsencode(args)] # os.PathLike -> [str] else: args = list(args) if shell: # On Android the default shell is at '/system/bin/sh'. unix_shell = ( '/system/bin/sh' if hasattr(sys, 'getandroidapilevel') else '/bin/sh' ) args = [unix_shell, "-c"] + args if executable: args[0] = executable if executable is None: executable = args[0] self._loop.install_sigchld() # For transferring possible exec failure from child to parent # The first char specifies the exception type: 0 means # OSError, 1 means some other error. errpipe_read, errpipe_write = self.pipe_cloexec() # errpipe_write must not be in the standard io 0, 1, or 2 fd range. low_fds_to_close = [] while errpipe_write < 3: low_fds_to_close.append(errpipe_write) errpipe_write = os.dup(errpipe_write) for low_fd in low_fds_to_close: os.close(low_fd) try: try: gc_was_enabled = gc.isenabled() # Disable gc to avoid bug where gc -> file_dealloc -> # write to stderr -> hang. http://bugs.python.org/issue1336 gc.disable() try: self.pid = fork_and_watch(self._on_child, self._loop, True, fork) except: if gc_was_enabled: gc.enable() raise if self.pid == 0: # Child # In various places on the child side of things, we catch OSError # and add attributes to it that detail where in the process we failed; # like all exceptions until we have exec'd, this exception is pickled # and sent to the parent to raise in the calling process. # The parent uses this to decide how to treat that exception, # adjusting certain information about it as needed. # # Python 3.11.8 --- yes, a minor patch release --- stopped # letting the 'filename' parameter get set in the resulting # exception for many cases. We're not quite interpreting this # the same way the stdlib is, I'm sure, but this makes the stdlib # tests pass. # XXX: Technically we're doing a lot of stuff here that # may not be safe to do before a exec(), depending on the OS. # CPython 3 goes to great lengths to precompute a lot # of this info before the fork and pass it all to C functions that # try hard not to call things like malloc(). (Of course, # CPython 2 pretty much did what we're doing.) try: # Close parent's pipe ends if p2cwrite != -1: os.close(p2cwrite) if c2pread != -1: os.close(c2pread) if errread != -1: os.close(errread) os.close(errpipe_read) # When duping fds, if there arises a situation # where one of the fds is either 0, 1 or 2, it # is possible that it is overwritten (#12607). if c2pwrite == 0: c2pwrite = os.dup(c2pwrite) _set_inheritable(c2pwrite, False) while errwrite in (0, 1): errwrite = os.dup(errwrite) _set_inheritable(errwrite, False) # Dup fds for child def _dup2(existing, desired): # dup2() removes the CLOEXEC flag but # we must do it ourselves if dup2() # would be a no-op (issue #10806). if existing == desired: self._set_cloexec_flag(existing, False) elif existing != -1: os.dup2(existing, desired) try: self._remove_nonblock_flag(desired) except OSError: # Ignore EBADF, it may not actually be # open yet. # Tested beginning in 3.7.0b3 test_subprocess.py pass _dup2(p2cread, 0) _dup2(c2pwrite, 1) _dup2(errwrite, 2) # Close pipe fds. Make sure we don't close the # same fd more than once, or standard fds. if not True: closed = set([None]) for fd in (p2cread, c2pwrite, errwrite): if fd not in closed and fd > 2: os.close(fd) closed.add(fd) # Python 3 (with a working set_inheritable): # We no longer manually close p2cread, # c2pwrite, and errwrite here as # _close_open_fds takes care when it is # not already non-inheritable. if cwd is not None: try: os.chdir(cwd) except OSError as e: e._failed_chdir = True raise # Python 3.9 if umask >= 0: os.umask(umask) # XXX: CPython does _Py_RestoreSignals here. # Then setsid() based on ??? try: if gids: os.setgroups(gids) if gid: os.setregid(gid, gid) if uid: os.setreuid(uid, uid) if process_group is not None: os.setpgid(0, process_group) except OSError as e: e._failed_chuser = True raise if preexec_fn: preexec_fn() # Close all other fds, if asked for. This must be done # after preexec_fn runs. if close_fds: fds_to_keep = set(pass_fds) fds_to_keep.add(errpipe_write) self._close_fds(fds_to_keep, errpipe_write) if restore_signals: # restore the documented signals back to sig_dfl; # not all will be defined on every platform for sig in 'SIGPIPE', 'SIGXFZ', 'SIGXFSZ': sig = getattr(signal, sig, None) if sig is not None: signal.signal(sig, signal.SIG_DFL) if start_new_session: os.setsid() try: if env is None: os.execvp(executable, args) else: # Python 3.6 started testing for # bytes values in the env; it also # started encoding strs using # fsencode and using a lower-level # API that takes a list of keys # and values. We don't have access # to that API, so we go the reverse direction. env = {os.fsdecode(k) if isinstance(k, bytes) else k: os.fsdecode(v) if isinstance(v, bytes) else v for k, v in env.items()} os.execvpe(executable, args, env) except OSError as e: e._failed_exec = True raise except: exc_type, exc_value, tb = sys.exc_info() # Save the traceback and attach it to the exception object exc_lines = traceback.format_exception(exc_type, exc_value, tb) exc_value.child_traceback = ''.join(exc_lines) os.write(errpipe_write, pickle.dumps(exc_value)) finally: # Make sure that the process exits no matter what. # The return code does not matter much as it won't be # reported to the application os._exit(1) # Parent self._child_created = True if gc_was_enabled: gc.enable() finally: # be sure the FD is closed no matter what os.close(errpipe_write) # self._devnull is not always defined. devnull_fd = getattr(self, '_devnull', None) if p2cread != -1 and p2cwrite != -1 and p2cread != devnull_fd: os.close(p2cread) if c2pwrite != -1 and c2pread != -1 and c2pwrite != devnull_fd: os.close(c2pwrite) if errwrite != -1 and errread != -1 and errwrite != devnull_fd: os.close(errwrite) if devnull_fd is not None: os.close(devnull_fd) # Prevent a double close of these fds from __init__ on error. self._closed_child_pipe_fds = True # Wait for exec to fail or succeed; possibly raising exception errpipe_read = FileObject(errpipe_read, 'rb') data = errpipe_read.read() finally: try: if hasattr(errpipe_read, 'close'): errpipe_read.close() else: os.close(errpipe_read) except OSError: # Especially on PyPy, we sometimes see the above # `os.close(errpipe_read)` raise an OSError. # It's not entirely clear why, but it happens in # InterprocessSignalTests.test_main sometimes, which must mean # we have some sort of race condition. pass finally: errpipe_read = -1 if data != b"": self.wait() child_exception = pickle.loads(data) for fd in (p2cwrite, c2pread, errread): if fd is not None and fd != -1: os.close(fd) if isinstance(child_exception, OSError): child_exception.filename = executable if hasattr(child_exception, '_failed_chdir'): child_exception.filename = cwd if getattr(child_exception, '_failed_chuser', False): child_exception.filename = None > raise child_exception E OSError: [Errno 8] Exec format error: 'locust' /usr/lib/python3/dist-packages/gevent/subprocess.py:1838: OSError ______ StandaloneIntegrationTests.test_headless_spawn_options_wo_run_time ______ self = @unittest.skipIf(os.name == "nt", reason="Signal handling on windows is hard") def test_headless_spawn_options_wo_run_time(self): with mock_locustfile() as mocked: > proc = subprocess.Popen( [ "locust", "-f", mocked.file_path, "--host", "https://test.com/", "--headless", "--exit-code-on-error", "0", ], stdout=PIPE, stderr=PIPE, text=True, ) locust/test/test_main.py:421: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3/dist-packages/gevent/subprocess.py:808: in __init__ self._execute_child(args, executable, preexec_fn, close_fds, _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = args = ['locust', '-f', '/build/reproducible-path/locust-2.24.0/locust/test/mock_locustfile_1715256375_3209193_20566.py', '--host', 'https://test.com/', '--headless', ...] executable = 'locust', preexec_fn = None, close_fds = True, pass_fds = () cwd = None, env = None, universal_newlines = None, startupinfo = None creationflags = 0, shell = False, p2cread = -1, p2cwrite = -1, c2pread = 11 c2pwrite = 80, errread = 81, errwrite = 82, restore_signals = True, gid = None gids = None, uid = None, umask = -1, start_new_session = False process_group = None def _execute_child(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, universal_newlines, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, restore_signals, gid, gids, uid, umask, start_new_session, process_group): """Execute program (POSIX version)""" if isinstance(args, (str, bytes)): args = [args] elif isinstance(args, PathLike): if shell: raise TypeError('path-like args is not allowed when ' 'shell is true') args = [fsencode(args)] # os.PathLike -> [str] else: args = list(args) if shell: # On Android the default shell is at '/system/bin/sh'. unix_shell = ( '/system/bin/sh' if hasattr(sys, 'getandroidapilevel') else '/bin/sh' ) args = [unix_shell, "-c"] + args if executable: args[0] = executable if executable is None: executable = args[0] self._loop.install_sigchld() # For transferring possible exec failure from child to parent # The first char specifies the exception type: 0 means # OSError, 1 means some other error. errpipe_read, errpipe_write = self.pipe_cloexec() # errpipe_write must not be in the standard io 0, 1, or 2 fd range. low_fds_to_close = [] while errpipe_write < 3: low_fds_to_close.append(errpipe_write) errpipe_write = os.dup(errpipe_write) for low_fd in low_fds_to_close: os.close(low_fd) try: try: gc_was_enabled = gc.isenabled() # Disable gc to avoid bug where gc -> file_dealloc -> # write to stderr -> hang. http://bugs.python.org/issue1336 gc.disable() try: self.pid = fork_and_watch(self._on_child, self._loop, True, fork) except: if gc_was_enabled: gc.enable() raise if self.pid == 0: # Child # In various places on the child side of things, we catch OSError # and add attributes to it that detail where in the process we failed; # like all exceptions until we have exec'd, this exception is pickled # and sent to the parent to raise in the calling process. # The parent uses this to decide how to treat that exception, # adjusting certain information about it as needed. # # Python 3.11.8 --- yes, a minor patch release --- stopped # letting the 'filename' parameter get set in the resulting # exception for many cases. We're not quite interpreting this # the same way the stdlib is, I'm sure, but this makes the stdlib # tests pass. # XXX: Technically we're doing a lot of stuff here that # may not be safe to do before a exec(), depending on the OS. # CPython 3 goes to great lengths to precompute a lot # of this info before the fork and pass it all to C functions that # try hard not to call things like malloc(). (Of course, # CPython 2 pretty much did what we're doing.) try: # Close parent's pipe ends if p2cwrite != -1: os.close(p2cwrite) if c2pread != -1: os.close(c2pread) if errread != -1: os.close(errread) os.close(errpipe_read) # When duping fds, if there arises a situation # where one of the fds is either 0, 1 or 2, it # is possible that it is overwritten (#12607). if c2pwrite == 0: c2pwrite = os.dup(c2pwrite) _set_inheritable(c2pwrite, False) while errwrite in (0, 1): errwrite = os.dup(errwrite) _set_inheritable(errwrite, False) # Dup fds for child def _dup2(existing, desired): # dup2() removes the CLOEXEC flag but # we must do it ourselves if dup2() # would be a no-op (issue #10806). if existing == desired: self._set_cloexec_flag(existing, False) elif existing != -1: os.dup2(existing, desired) try: self._remove_nonblock_flag(desired) except OSError: # Ignore EBADF, it may not actually be # open yet. # Tested beginning in 3.7.0b3 test_subprocess.py pass _dup2(p2cread, 0) _dup2(c2pwrite, 1) _dup2(errwrite, 2) # Close pipe fds. Make sure we don't close the # same fd more than once, or standard fds. if not True: closed = set([None]) for fd in (p2cread, c2pwrite, errwrite): if fd not in closed and fd > 2: os.close(fd) closed.add(fd) # Python 3 (with a working set_inheritable): # We no longer manually close p2cread, # c2pwrite, and errwrite here as # _close_open_fds takes care when it is # not already non-inheritable. if cwd is not None: try: os.chdir(cwd) except OSError as e: e._failed_chdir = True raise # Python 3.9 if umask >= 0: os.umask(umask) # XXX: CPython does _Py_RestoreSignals here. # Then setsid() based on ??? try: if gids: os.setgroups(gids) if gid: os.setregid(gid, gid) if uid: os.setreuid(uid, uid) if process_group is not None: os.setpgid(0, process_group) except OSError as e: e._failed_chuser = True raise if preexec_fn: preexec_fn() # Close all other fds, if asked for. This must be done # after preexec_fn runs. if close_fds: fds_to_keep = set(pass_fds) fds_to_keep.add(errpipe_write) self._close_fds(fds_to_keep, errpipe_write) if restore_signals: # restore the documented signals back to sig_dfl; # not all will be defined on every platform for sig in 'SIGPIPE', 'SIGXFZ', 'SIGXFSZ': sig = getattr(signal, sig, None) if sig is not None: signal.signal(sig, signal.SIG_DFL) if start_new_session: os.setsid() try: if env is None: os.execvp(executable, args) else: # Python 3.6 started testing for # bytes values in the env; it also # started encoding strs using # fsencode and using a lower-level # API that takes a list of keys # and values. We don't have access # to that API, so we go the reverse direction. env = {os.fsdecode(k) if isinstance(k, bytes) else k: os.fsdecode(v) if isinstance(v, bytes) else v for k, v in env.items()} os.execvpe(executable, args, env) except OSError as e: e._failed_exec = True raise except: exc_type, exc_value, tb = sys.exc_info() # Save the traceback and attach it to the exception object exc_lines = traceback.format_exception(exc_type, exc_value, tb) exc_value.child_traceback = ''.join(exc_lines) os.write(errpipe_write, pickle.dumps(exc_value)) finally: # Make sure that the process exits no matter what. # The return code does not matter much as it won't be # reported to the application os._exit(1) # Parent self._child_created = True if gc_was_enabled: gc.enable() finally: # be sure the FD is closed no matter what os.close(errpipe_write) # self._devnull is not always defined. devnull_fd = getattr(self, '_devnull', None) if p2cread != -1 and p2cwrite != -1 and p2cread != devnull_fd: os.close(p2cread) if c2pwrite != -1 and c2pread != -1 and c2pwrite != devnull_fd: os.close(c2pwrite) if errwrite != -1 and errread != -1 and errwrite != devnull_fd: os.close(errwrite) if devnull_fd is not None: os.close(devnull_fd) # Prevent a double close of these fds from __init__ on error. self._closed_child_pipe_fds = True # Wait for exec to fail or succeed; possibly raising exception errpipe_read = FileObject(errpipe_read, 'rb') data = errpipe_read.read() finally: try: if hasattr(errpipe_read, 'close'): errpipe_read.close() else: os.close(errpipe_read) except OSError: # Especially on PyPy, we sometimes see the above # `os.close(errpipe_read)` raise an OSError. # It's not entirely clear why, but it happens in # InterprocessSignalTests.test_main sometimes, which must mean # we have some sort of race condition. pass finally: errpipe_read = -1 if data != b"": self.wait() child_exception = pickle.loads(data) for fd in (p2cwrite, c2pread, errread): if fd is not None and fd != -1: os.close(fd) if isinstance(child_exception, OSError): child_exception.filename = executable if hasattr(child_exception, '_failed_chdir'): child_exception.filename = cwd if getattr(child_exception, '_failed_chuser', False): child_exception.filename = None > raise child_exception E OSError: [Errno 8] Exec format error: 'locust' /usr/lib/python3/dist-packages/gevent/subprocess.py:1838: OSError ___________________ StandaloneIntegrationTests.test_help_arg ___________________ self = def test_help_arg(self): > output = subprocess.check_output( ["locust", "--help"], stderr=subprocess.STDOUT, timeout=5, text=True, ).strip() locust/test/test_main.py:72: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3/dist-packages/gevent/subprocess.py:405: in check_output with Popen(*popenargs, stdout=PIPE, **kwargs) as process: /usr/lib/python3/dist-packages/gevent/subprocess.py:808: in __init__ self._execute_child(args, executable, preexec_fn, close_fds, _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = args = ['locust', '--help'], executable = 'locust', preexec_fn = None close_fds = True, pass_fds = (), cwd = None, env = None universal_newlines = None, startupinfo = None, creationflags = 0, shell = False p2cread = -1, p2cwrite = -1, c2pread = 11, c2pwrite = 80, errread = -1 errwrite = 80, restore_signals = True, gid = None, gids = None, uid = None umask = -1, start_new_session = False, process_group = None def _execute_child(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, universal_newlines, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, restore_signals, gid, gids, uid, umask, start_new_session, process_group): """Execute program (POSIX version)""" if isinstance(args, (str, bytes)): args = [args] elif isinstance(args, PathLike): if shell: raise TypeError('path-like args is not allowed when ' 'shell is true') args = [fsencode(args)] # os.PathLike -> [str] else: args = list(args) if shell: # On Android the default shell is at '/system/bin/sh'. unix_shell = ( '/system/bin/sh' if hasattr(sys, 'getandroidapilevel') else '/bin/sh' ) args = [unix_shell, "-c"] + args if executable: args[0] = executable if executable is None: executable = args[0] self._loop.install_sigchld() # For transferring possible exec failure from child to parent # The first char specifies the exception type: 0 means # OSError, 1 means some other error. errpipe_read, errpipe_write = self.pipe_cloexec() # errpipe_write must not be in the standard io 0, 1, or 2 fd range. low_fds_to_close = [] while errpipe_write < 3: low_fds_to_close.append(errpipe_write) errpipe_write = os.dup(errpipe_write) for low_fd in low_fds_to_close: os.close(low_fd) try: try: gc_was_enabled = gc.isenabled() # Disable gc to avoid bug where gc -> file_dealloc -> # write to stderr -> hang. http://bugs.python.org/issue1336 gc.disable() try: self.pid = fork_and_watch(self._on_child, self._loop, True, fork) except: if gc_was_enabled: gc.enable() raise if self.pid == 0: # Child # In various places on the child side of things, we catch OSError # and add attributes to it that detail where in the process we failed; # like all exceptions until we have exec'd, this exception is pickled # and sent to the parent to raise in the calling process. # The parent uses this to decide how to treat that exception, # adjusting certain information about it as needed. # # Python 3.11.8 --- yes, a minor patch release --- stopped # letting the 'filename' parameter get set in the resulting # exception for many cases. We're not quite interpreting this # the same way the stdlib is, I'm sure, but this makes the stdlib # tests pass. # XXX: Technically we're doing a lot of stuff here that # may not be safe to do before a exec(), depending on the OS. # CPython 3 goes to great lengths to precompute a lot # of this info before the fork and pass it all to C functions that # try hard not to call things like malloc(). (Of course, # CPython 2 pretty much did what we're doing.) try: # Close parent's pipe ends if p2cwrite != -1: os.close(p2cwrite) if c2pread != -1: os.close(c2pread) if errread != -1: os.close(errread) os.close(errpipe_read) # When duping fds, if there arises a situation # where one of the fds is either 0, 1 or 2, it # is possible that it is overwritten (#12607). if c2pwrite == 0: c2pwrite = os.dup(c2pwrite) _set_inheritable(c2pwrite, False) while errwrite in (0, 1): errwrite = os.dup(errwrite) _set_inheritable(errwrite, False) # Dup fds for child def _dup2(existing, desired): # dup2() removes the CLOEXEC flag but # we must do it ourselves if dup2() # would be a no-op (issue #10806). if existing == desired: self._set_cloexec_flag(existing, False) elif existing != -1: os.dup2(existing, desired) try: self._remove_nonblock_flag(desired) except OSError: # Ignore EBADF, it may not actually be # open yet. # Tested beginning in 3.7.0b3 test_subprocess.py pass _dup2(p2cread, 0) _dup2(c2pwrite, 1) _dup2(errwrite, 2) # Close pipe fds. Make sure we don't close the # same fd more than once, or standard fds. if not True: closed = set([None]) for fd in (p2cread, c2pwrite, errwrite): if fd not in closed and fd > 2: os.close(fd) closed.add(fd) # Python 3 (with a working set_inheritable): # We no longer manually close p2cread, # c2pwrite, and errwrite here as # _close_open_fds takes care when it is # not already non-inheritable. if cwd is not None: try: os.chdir(cwd) except OSError as e: e._failed_chdir = True raise # Python 3.9 if umask >= 0: os.umask(umask) # XXX: CPython does _Py_RestoreSignals here. # Then setsid() based on ??? try: if gids: os.setgroups(gids) if gid: os.setregid(gid, gid) if uid: os.setreuid(uid, uid) if process_group is not None: os.setpgid(0, process_group) except OSError as e: e._failed_chuser = True raise if preexec_fn: preexec_fn() # Close all other fds, if asked for. This must be done # after preexec_fn runs. if close_fds: fds_to_keep = set(pass_fds) fds_to_keep.add(errpipe_write) self._close_fds(fds_to_keep, errpipe_write) if restore_signals: # restore the documented signals back to sig_dfl; # not all will be defined on every platform for sig in 'SIGPIPE', 'SIGXFZ', 'SIGXFSZ': sig = getattr(signal, sig, None) if sig is not None: signal.signal(sig, signal.SIG_DFL) if start_new_session: os.setsid() try: if env is None: os.execvp(executable, args) else: # Python 3.6 started testing for # bytes values in the env; it also # started encoding strs using # fsencode and using a lower-level # API that takes a list of keys # and values. We don't have access # to that API, so we go the reverse direction. env = {os.fsdecode(k) if isinstance(k, bytes) else k: os.fsdecode(v) if isinstance(v, bytes) else v for k, v in env.items()} os.execvpe(executable, args, env) except OSError as e: e._failed_exec = True raise except: exc_type, exc_value, tb = sys.exc_info() # Save the traceback and attach it to the exception object exc_lines = traceback.format_exception(exc_type, exc_value, tb) exc_value.child_traceback = ''.join(exc_lines) os.write(errpipe_write, pickle.dumps(exc_value)) finally: # Make sure that the process exits no matter what. # The return code does not matter much as it won't be # reported to the application os._exit(1) # Parent self._child_created = True if gc_was_enabled: gc.enable() finally: # be sure the FD is closed no matter what os.close(errpipe_write) # self._devnull is not always defined. devnull_fd = getattr(self, '_devnull', None) if p2cread != -1 and p2cwrite != -1 and p2cread != devnull_fd: os.close(p2cread) if c2pwrite != -1 and c2pread != -1 and c2pwrite != devnull_fd: os.close(c2pwrite) if errwrite != -1 and errread != -1 and errwrite != devnull_fd: os.close(errwrite) if devnull_fd is not None: os.close(devnull_fd) # Prevent a double close of these fds from __init__ on error. self._closed_child_pipe_fds = True # Wait for exec to fail or succeed; possibly raising exception errpipe_read = FileObject(errpipe_read, 'rb') data = errpipe_read.read() finally: try: if hasattr(errpipe_read, 'close'): errpipe_read.close() else: os.close(errpipe_read) except OSError: # Especially on PyPy, we sometimes see the above # `os.close(errpipe_read)` raise an OSError. # It's not entirely clear why, but it happens in # InterprocessSignalTests.test_main sometimes, which must mean # we have some sort of race condition. pass finally: errpipe_read = -1 if data != b"": self.wait() child_exception = pickle.loads(data) for fd in (p2cwrite, c2pread, errread): if fd is not None and fd != -1: os.close(fd) if isinstance(child_exception, OSError): child_exception.filename = executable if hasattr(child_exception, '_failed_chdir'): child_exception.filename = cwd if getattr(child_exception, '_failed_chuser', False): child_exception.filename = None > raise child_exception E OSError: [Errno 8] Exec format error: 'locust' /usr/lib/python3/dist-packages/gevent/subprocess.py:1838: OSError ______________ StandaloneIntegrationTests.test_html_report_option ______________ self = def test_html_report_option(self): with mock_locustfile() as mocked: with temporary_file("", suffix=".html") as html_report_file_path: try: > output = subprocess.check_output( [ "locust", "-f", mocked.file_path, "--legacy-ui", "--host", "https://test.com/", "--run-time", "2s", "--headless", "--exit-code-on-error", "0", "--html", html_report_file_path, ], stderr=subprocess.STDOUT, timeout=10, text=True, ).strip() locust/test/test_main.py:1088: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3/dist-packages/gevent/subprocess.py:405: in check_output with Popen(*popenargs, stdout=PIPE, **kwargs) as process: /usr/lib/python3/dist-packages/gevent/subprocess.py:808: in __init__ self._execute_child(args, executable, preexec_fn, close_fds, _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = args = ['locust', '-f', '/build/reproducible-path/locust-2.24.0/locust/test/mock_locustfile_1715256375_8955183_45841.py', '--legacy-ui', '--host', 'https://test.com/', ...] executable = 'locust', preexec_fn = None, close_fds = True, pass_fds = () cwd = None, env = None, universal_newlines = None, startupinfo = None creationflags = 0, shell = False, p2cread = -1, p2cwrite = -1, c2pread = 11 c2pwrite = 80, errread = -1, errwrite = 80, restore_signals = True, gid = None gids = None, uid = None, umask = -1, start_new_session = False process_group = None def _execute_child(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, universal_newlines, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, restore_signals, gid, gids, uid, umask, start_new_session, process_group): """Execute program (POSIX version)""" if isinstance(args, (str, bytes)): args = [args] elif isinstance(args, PathLike): if shell: raise TypeError('path-like args is not allowed when ' 'shell is true') args = [fsencode(args)] # os.PathLike -> [str] else: args = list(args) if shell: # On Android the default shell is at '/system/bin/sh'. unix_shell = ( '/system/bin/sh' if hasattr(sys, 'getandroidapilevel') else '/bin/sh' ) args = [unix_shell, "-c"] + args if executable: args[0] = executable if executable is None: executable = args[0] self._loop.install_sigchld() # For transferring possible exec failure from child to parent # The first char specifies the exception type: 0 means # OSError, 1 means some other error. errpipe_read, errpipe_write = self.pipe_cloexec() # errpipe_write must not be in the standard io 0, 1, or 2 fd range. low_fds_to_close = [] while errpipe_write < 3: low_fds_to_close.append(errpipe_write) errpipe_write = os.dup(errpipe_write) for low_fd in low_fds_to_close: os.close(low_fd) try: try: gc_was_enabled = gc.isenabled() # Disable gc to avoid bug where gc -> file_dealloc -> # write to stderr -> hang. http://bugs.python.org/issue1336 gc.disable() try: self.pid = fork_and_watch(self._on_child, self._loop, True, fork) except: if gc_was_enabled: gc.enable() raise if self.pid == 0: # Child # In various places on the child side of things, we catch OSError # and add attributes to it that detail where in the process we failed; # like all exceptions until we have exec'd, this exception is pickled # and sent to the parent to raise in the calling process. # The parent uses this to decide how to treat that exception, # adjusting certain information about it as needed. # # Python 3.11.8 --- yes, a minor patch release --- stopped # letting the 'filename' parameter get set in the resulting # exception for many cases. We're not quite interpreting this # the same way the stdlib is, I'm sure, but this makes the stdlib # tests pass. # XXX: Technically we're doing a lot of stuff here that # may not be safe to do before a exec(), depending on the OS. # CPython 3 goes to great lengths to precompute a lot # of this info before the fork and pass it all to C functions that # try hard not to call things like malloc(). (Of course, # CPython 2 pretty much did what we're doing.) try: # Close parent's pipe ends if p2cwrite != -1: os.close(p2cwrite) if c2pread != -1: os.close(c2pread) if errread != -1: os.close(errread) os.close(errpipe_read) # When duping fds, if there arises a situation # where one of the fds is either 0, 1 or 2, it # is possible that it is overwritten (#12607). if c2pwrite == 0: c2pwrite = os.dup(c2pwrite) _set_inheritable(c2pwrite, False) while errwrite in (0, 1): errwrite = os.dup(errwrite) _set_inheritable(errwrite, False) # Dup fds for child def _dup2(existing, desired): # dup2() removes the CLOEXEC flag but # we must do it ourselves if dup2() # would be a no-op (issue #10806). if existing == desired: self._set_cloexec_flag(existing, False) elif existing != -1: os.dup2(existing, desired) try: self._remove_nonblock_flag(desired) except OSError: # Ignore EBADF, it may not actually be # open yet. # Tested beginning in 3.7.0b3 test_subprocess.py pass _dup2(p2cread, 0) _dup2(c2pwrite, 1) _dup2(errwrite, 2) # Close pipe fds. Make sure we don't close the # same fd more than once, or standard fds. if not True: closed = set([None]) for fd in (p2cread, c2pwrite, errwrite): if fd not in closed and fd > 2: os.close(fd) closed.add(fd) # Python 3 (with a working set_inheritable): # We no longer manually close p2cread, # c2pwrite, and errwrite here as # _close_open_fds takes care when it is # not already non-inheritable. if cwd is not None: try: os.chdir(cwd) except OSError as e: e._failed_chdir = True raise # Python 3.9 if umask >= 0: os.umask(umask) # XXX: CPython does _Py_RestoreSignals here. # Then setsid() based on ??? try: if gids: os.setgroups(gids) if gid: os.setregid(gid, gid) if uid: os.setreuid(uid, uid) if process_group is not None: os.setpgid(0, process_group) except OSError as e: e._failed_chuser = True raise if preexec_fn: preexec_fn() # Close all other fds, if asked for. This must be done # after preexec_fn runs. if close_fds: fds_to_keep = set(pass_fds) fds_to_keep.add(errpipe_write) self._close_fds(fds_to_keep, errpipe_write) if restore_signals: # restore the documented signals back to sig_dfl; # not all will be defined on every platform for sig in 'SIGPIPE', 'SIGXFZ', 'SIGXFSZ': sig = getattr(signal, sig, None) if sig is not None: signal.signal(sig, signal.SIG_DFL) if start_new_session: os.setsid() try: if env is None: os.execvp(executable, args) else: # Python 3.6 started testing for # bytes values in the env; it also # started encoding strs using # fsencode and using a lower-level # API that takes a list of keys # and values. We don't have access # to that API, so we go the reverse direction. env = {os.fsdecode(k) if isinstance(k, bytes) else k: os.fsdecode(v) if isinstance(v, bytes) else v for k, v in env.items()} os.execvpe(executable, args, env) except OSError as e: e._failed_exec = True raise except: exc_type, exc_value, tb = sys.exc_info() # Save the traceback and attach it to the exception object exc_lines = traceback.format_exception(exc_type, exc_value, tb) exc_value.child_traceback = ''.join(exc_lines) os.write(errpipe_write, pickle.dumps(exc_value)) finally: # Make sure that the process exits no matter what. # The return code does not matter much as it won't be # reported to the application os._exit(1) # Parent self._child_created = True if gc_was_enabled: gc.enable() finally: # be sure the FD is closed no matter what os.close(errpipe_write) # self._devnull is not always defined. devnull_fd = getattr(self, '_devnull', None) if p2cread != -1 and p2cwrite != -1 and p2cread != devnull_fd: os.close(p2cread) if c2pwrite != -1 and c2pread != -1 and c2pwrite != devnull_fd: os.close(c2pwrite) if errwrite != -1 and errread != -1 and errwrite != devnull_fd: os.close(errwrite) if devnull_fd is not None: os.close(devnull_fd) # Prevent a double close of these fds from __init__ on error. self._closed_child_pipe_fds = True # Wait for exec to fail or succeed; possibly raising exception errpipe_read = FileObject(errpipe_read, 'rb') data = errpipe_read.read() finally: try: if hasattr(errpipe_read, 'close'): errpipe_read.close() else: os.close(errpipe_read) except OSError: # Especially on PyPy, we sometimes see the above # `os.close(errpipe_read)` raise an OSError. # It's not entirely clear why, but it happens in # InterprocessSignalTests.test_main sometimes, which must mean # we have some sort of race condition. pass finally: errpipe_read = -1 if data != b"": self.wait() child_exception = pickle.loads(data) for fd in (p2cwrite, c2pread, errread): if fd is not None and fd != -1: os.close(fd) if isinstance(child_exception, OSError): child_exception.filename = executable if hasattr(child_exception, '_failed_chdir'): child_exception.filename = cwd if getattr(child_exception, '_failed_chuser', False): child_exception.filename = None > raise child_exception E OSError: [Errno 8] Exec format error: 'locust' /usr/lib/python3/dist-packages/gevent/subprocess.py:1838: OSError ____________________ StandaloneIntegrationTests.test_input _____________________ self = @unittest.skipIf(os.name == "nt", reason="termios doesnt exist on windows, and thus we cannot import pty") def test_input(self): import pty LOCUSTFILE_CONTENT = textwrap.dedent( """ from locust import User, TaskSet, task, between class UserSubclass(User): wait_time = between(0.2, 0.8) @task def t(self): print("Test task is running") """ ) with mock_locustfile(content=LOCUSTFILE_CONTENT) as mocked: stdin_m, stdin_s = pty.openpty() stdin = os.fdopen(stdin_m, "wb", 0) proc = subprocess.Popen( " ".join( [ "locust", "-f", mocked.file_path, "--headless", "--run-time", "7s", "-u", "0", "--loglevel", "INFO", ] ), stderr=STDOUT, stdin=stdin_s, stdout=PIPE, shell=True, text=True, ) gevent.sleep(1) stdin.write(b"w") gevent.sleep(1) stdin.write(b"W") gevent.sleep(1) stdin.write(b"s") gevent.sleep(1) stdin.write(b"S") gevent.sleep(1) # This should not do anything since we are already at zero users stdin.write(b"S") gevent.sleep(1) output = proc.communicate()[0] stdin.close() > self.assertIn("Ramping to 1 users at a rate of 100.00 per second", output) E AssertionError: 'Ramping to 1 users at a rate of 100.00 per second' not found in '/build/reproducible-path/locust-2.24.0/debian/locust: line 2: from: command not found\n/build/reproducible-path/locust-2.24.0/debian/locust: line 5: syntax error: unexpected end of file\n' locust/test/test_main.py:922: AssertionError _________ StandaloneIntegrationTests.test_invalid_percentile_parameter _________ self = def test_invalid_percentile_parameter(self): with temporary_file( content=textwrap.dedent( """ from locust import User, task, constant, events from locust.stats import PERCENTILES_TO_CHART PERCENTILES_TO_CHART[0] = 1.2 class TestUser(User): wait_time = constant(3) @task def my_task(self): print("running my_task()") """ ) ) as file_path: > proc = subprocess.Popen(["locust", "-f", file_path, "--autostart"], stdout=PIPE, stderr=PIPE, text=True) locust/test/test_main.py:287: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3/dist-packages/gevent/subprocess.py:808: in __init__ self._execute_child(args, executable, preexec_fn, close_fds, _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = args = ['locust', '-f', '/tmp/tmpj1_te26b_locustfile.py', '--autostart'] executable = 'locust', preexec_fn = None, close_fds = True, pass_fds = () cwd = None, env = None, universal_newlines = None, startupinfo = None creationflags = 0, shell = False, p2cread = -1, p2cwrite = -1, c2pread = 11 c2pwrite = 81, errread = 82, errwrite = 83, restore_signals = True, gid = None gids = None, uid = None, umask = -1, start_new_session = False process_group = None def _execute_child(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, universal_newlines, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, restore_signals, gid, gids, uid, umask, start_new_session, process_group): """Execute program (POSIX version)""" if isinstance(args, (str, bytes)): args = [args] elif isinstance(args, PathLike): if shell: raise TypeError('path-like args is not allowed when ' 'shell is true') args = [fsencode(args)] # os.PathLike -> [str] else: args = list(args) if shell: # On Android the default shell is at '/system/bin/sh'. unix_shell = ( '/system/bin/sh' if hasattr(sys, 'getandroidapilevel') else '/bin/sh' ) args = [unix_shell, "-c"] + args if executable: args[0] = executable if executable is None: executable = args[0] self._loop.install_sigchld() # For transferring possible exec failure from child to parent # The first char specifies the exception type: 0 means # OSError, 1 means some other error. errpipe_read, errpipe_write = self.pipe_cloexec() # errpipe_write must not be in the standard io 0, 1, or 2 fd range. low_fds_to_close = [] while errpipe_write < 3: low_fds_to_close.append(errpipe_write) errpipe_write = os.dup(errpipe_write) for low_fd in low_fds_to_close: os.close(low_fd) try: try: gc_was_enabled = gc.isenabled() # Disable gc to avoid bug where gc -> file_dealloc -> # write to stderr -> hang. http://bugs.python.org/issue1336 gc.disable() try: self.pid = fork_and_watch(self._on_child, self._loop, True, fork) except: if gc_was_enabled: gc.enable() raise if self.pid == 0: # Child # In various places on the child side of things, we catch OSError # and add attributes to it that detail where in the process we failed; # like all exceptions until we have exec'd, this exception is pickled # and sent to the parent to raise in the calling process. # The parent uses this to decide how to treat that exception, # adjusting certain information about it as needed. # # Python 3.11.8 --- yes, a minor patch release --- stopped # letting the 'filename' parameter get set in the resulting # exception for many cases. We're not quite interpreting this # the same way the stdlib is, I'm sure, but this makes the stdlib # tests pass. # XXX: Technically we're doing a lot of stuff here that # may not be safe to do before a exec(), depending on the OS. # CPython 3 goes to great lengths to precompute a lot # of this info before the fork and pass it all to C functions that # try hard not to call things like malloc(). (Of course, # CPython 2 pretty much did what we're doing.) try: # Close parent's pipe ends if p2cwrite != -1: os.close(p2cwrite) if c2pread != -1: os.close(c2pread) if errread != -1: os.close(errread) os.close(errpipe_read) # When duping fds, if there arises a situation # where one of the fds is either 0, 1 or 2, it # is possible that it is overwritten (#12607). if c2pwrite == 0: c2pwrite = os.dup(c2pwrite) _set_inheritable(c2pwrite, False) while errwrite in (0, 1): errwrite = os.dup(errwrite) _set_inheritable(errwrite, False) # Dup fds for child def _dup2(existing, desired): # dup2() removes the CLOEXEC flag but # we must do it ourselves if dup2() # would be a no-op (issue #10806). if existing == desired: self._set_cloexec_flag(existing, False) elif existing != -1: os.dup2(existing, desired) try: self._remove_nonblock_flag(desired) except OSError: # Ignore EBADF, it may not actually be # open yet. # Tested beginning in 3.7.0b3 test_subprocess.py pass _dup2(p2cread, 0) _dup2(c2pwrite, 1) _dup2(errwrite, 2) # Close pipe fds. Make sure we don't close the # same fd more than once, or standard fds. if not True: closed = set([None]) for fd in (p2cread, c2pwrite, errwrite): if fd not in closed and fd > 2: os.close(fd) closed.add(fd) # Python 3 (with a working set_inheritable): # We no longer manually close p2cread, # c2pwrite, and errwrite here as # _close_open_fds takes care when it is # not already non-inheritable. if cwd is not None: try: os.chdir(cwd) except OSError as e: e._failed_chdir = True raise # Python 3.9 if umask >= 0: os.umask(umask) # XXX: CPython does _Py_RestoreSignals here. # Then setsid() based on ??? try: if gids: os.setgroups(gids) if gid: os.setregid(gid, gid) if uid: os.setreuid(uid, uid) if process_group is not None: os.setpgid(0, process_group) except OSError as e: e._failed_chuser = True raise if preexec_fn: preexec_fn() # Close all other fds, if asked for. This must be done # after preexec_fn runs. if close_fds: fds_to_keep = set(pass_fds) fds_to_keep.add(errpipe_write) self._close_fds(fds_to_keep, errpipe_write) if restore_signals: # restore the documented signals back to sig_dfl; # not all will be defined on every platform for sig in 'SIGPIPE', 'SIGXFZ', 'SIGXFSZ': sig = getattr(signal, sig, None) if sig is not None: signal.signal(sig, signal.SIG_DFL) if start_new_session: os.setsid() try: if env is None: os.execvp(executable, args) else: # Python 3.6 started testing for # bytes values in the env; it also # started encoding strs using # fsencode and using a lower-level # API that takes a list of keys # and values. We don't have access # to that API, so we go the reverse direction. env = {os.fsdecode(k) if isinstance(k, bytes) else k: os.fsdecode(v) if isinstance(v, bytes) else v for k, v in env.items()} os.execvpe(executable, args, env) except OSError as e: e._failed_exec = True raise except: exc_type, exc_value, tb = sys.exc_info() # Save the traceback and attach it to the exception object exc_lines = traceback.format_exception(exc_type, exc_value, tb) exc_value.child_traceback = ''.join(exc_lines) os.write(errpipe_write, pickle.dumps(exc_value)) finally: # Make sure that the process exits no matter what. # The return code does not matter much as it won't be # reported to the application os._exit(1) # Parent self._child_created = True if gc_was_enabled: gc.enable() finally: # be sure the FD is closed no matter what os.close(errpipe_write) # self._devnull is not always defined. devnull_fd = getattr(self, '_devnull', None) if p2cread != -1 and p2cwrite != -1 and p2cread != devnull_fd: os.close(p2cread) if c2pwrite != -1 and c2pread != -1 and c2pwrite != devnull_fd: os.close(c2pwrite) if errwrite != -1 and errread != -1 and errwrite != devnull_fd: os.close(errwrite) if devnull_fd is not None: os.close(devnull_fd) # Prevent a double close of these fds from __init__ on error. self._closed_child_pipe_fds = True # Wait for exec to fail or succeed; possibly raising exception errpipe_read = FileObject(errpipe_read, 'rb') data = errpipe_read.read() finally: try: if hasattr(errpipe_read, 'close'): errpipe_read.close() else: os.close(errpipe_read) except OSError: # Especially on PyPy, we sometimes see the above # `os.close(errpipe_read)` raise an OSError. # It's not entirely clear why, but it happens in # InterprocessSignalTests.test_main sometimes, which must mean # we have some sort of race condition. pass finally: errpipe_read = -1 if data != b"": self.wait() child_exception = pickle.loads(data) for fd in (p2cwrite, c2pread, errread): if fd is not None and fd != -1: os.close(fd) if isinstance(child_exception, OSError): child_exception.filename = executable if hasattr(child_exception, '_failed_chdir'): child_exception.filename = cwd if getattr(child_exception, '_failed_chuser', False): child_exception.filename = None > raise child_exception E OSError: [Errno 8] Exec format error: 'locust' /usr/lib/python3/dist-packages/gevent/subprocess.py:1838: OSError _________ StandaloneIntegrationTests.test_invalid_stop_timeout_string __________ self = def test_invalid_stop_timeout_string(self): with mock_locustfile() as mocked: > proc = subprocess.Popen( [ "locust", "-f", mocked.file_path, "--host", "https://test.com/", "--stop-timeout", "asdf1", ], stdout=PIPE, stderr=PIPE, text=True, ) locust/test/test_main.py:400: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3/dist-packages/gevent/subprocess.py:808: in __init__ self._execute_child(args, executable, preexec_fn, close_fds, _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = args = ['locust', '-f', '/build/reproducible-path/locust-2.24.0/locust/test/mock_locustfile_1715256382_4118147_49196.py', '--host', 'https://test.com/', '--stop-timeout', ...] executable = 'locust', preexec_fn = None, close_fds = True, pass_fds = () cwd = None, env = None, universal_newlines = None, startupinfo = None creationflags = 0, shell = False, p2cread = -1, p2cwrite = -1, c2pread = 11 c2pwrite = 81, errread = 82, errwrite = 83, restore_signals = True, gid = None gids = None, uid = None, umask = -1, start_new_session = False process_group = None def _execute_child(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, universal_newlines, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, restore_signals, gid, gids, uid, umask, start_new_session, process_group): """Execute program (POSIX version)""" if isinstance(args, (str, bytes)): args = [args] elif isinstance(args, PathLike): if shell: raise TypeError('path-like args is not allowed when ' 'shell is true') args = [fsencode(args)] # os.PathLike -> [str] else: args = list(args) if shell: # On Android the default shell is at '/system/bin/sh'. unix_shell = ( '/system/bin/sh' if hasattr(sys, 'getandroidapilevel') else '/bin/sh' ) args = [unix_shell, "-c"] + args if executable: args[0] = executable if executable is None: executable = args[0] self._loop.install_sigchld() # For transferring possible exec failure from child to parent # The first char specifies the exception type: 0 means # OSError, 1 means some other error. errpipe_read, errpipe_write = self.pipe_cloexec() # errpipe_write must not be in the standard io 0, 1, or 2 fd range. low_fds_to_close = [] while errpipe_write < 3: low_fds_to_close.append(errpipe_write) errpipe_write = os.dup(errpipe_write) for low_fd in low_fds_to_close: os.close(low_fd) try: try: gc_was_enabled = gc.isenabled() # Disable gc to avoid bug where gc -> file_dealloc -> # write to stderr -> hang. http://bugs.python.org/issue1336 gc.disable() try: self.pid = fork_and_watch(self._on_child, self._loop, True, fork) except: if gc_was_enabled: gc.enable() raise if self.pid == 0: # Child # In various places on the child side of things, we catch OSError # and add attributes to it that detail where in the process we failed; # like all exceptions until we have exec'd, this exception is pickled # and sent to the parent to raise in the calling process. # The parent uses this to decide how to treat that exception, # adjusting certain information about it as needed. # # Python 3.11.8 --- yes, a minor patch release --- stopped # letting the 'filename' parameter get set in the resulting # exception for many cases. We're not quite interpreting this # the same way the stdlib is, I'm sure, but this makes the stdlib # tests pass. # XXX: Technically we're doing a lot of stuff here that # may not be safe to do before a exec(), depending on the OS. # CPython 3 goes to great lengths to precompute a lot # of this info before the fork and pass it all to C functions that # try hard not to call things like malloc(). (Of course, # CPython 2 pretty much did what we're doing.) try: # Close parent's pipe ends if p2cwrite != -1: os.close(p2cwrite) if c2pread != -1: os.close(c2pread) if errread != -1: os.close(errread) os.close(errpipe_read) # When duping fds, if there arises a situation # where one of the fds is either 0, 1 or 2, it # is possible that it is overwritten (#12607). if c2pwrite == 0: c2pwrite = os.dup(c2pwrite) _set_inheritable(c2pwrite, False) while errwrite in (0, 1): errwrite = os.dup(errwrite) _set_inheritable(errwrite, False) # Dup fds for child def _dup2(existing, desired): # dup2() removes the CLOEXEC flag but # we must do it ourselves if dup2() # would be a no-op (issue #10806). if existing == desired: self._set_cloexec_flag(existing, False) elif existing != -1: os.dup2(existing, desired) try: self._remove_nonblock_flag(desired) except OSError: # Ignore EBADF, it may not actually be # open yet. # Tested beginning in 3.7.0b3 test_subprocess.py pass _dup2(p2cread, 0) _dup2(c2pwrite, 1) _dup2(errwrite, 2) # Close pipe fds. Make sure we don't close the # same fd more than once, or standard fds. if not True: closed = set([None]) for fd in (p2cread, c2pwrite, errwrite): if fd not in closed and fd > 2: os.close(fd) closed.add(fd) # Python 3 (with a working set_inheritable): # We no longer manually close p2cread, # c2pwrite, and errwrite here as # _close_open_fds takes care when it is # not already non-inheritable. if cwd is not None: try: os.chdir(cwd) except OSError as e: e._failed_chdir = True raise # Python 3.9 if umask >= 0: os.umask(umask) # XXX: CPython does _Py_RestoreSignals here. # Then setsid() based on ??? try: if gids: os.setgroups(gids) if gid: os.setregid(gid, gid) if uid: os.setreuid(uid, uid) if process_group is not None: os.setpgid(0, process_group) except OSError as e: e._failed_chuser = True raise if preexec_fn: preexec_fn() # Close all other fds, if asked for. This must be done # after preexec_fn runs. if close_fds: fds_to_keep = set(pass_fds) fds_to_keep.add(errpipe_write) self._close_fds(fds_to_keep, errpipe_write) if restore_signals: # restore the documented signals back to sig_dfl; # not all will be defined on every platform for sig in 'SIGPIPE', 'SIGXFZ', 'SIGXFSZ': sig = getattr(signal, sig, None) if sig is not None: signal.signal(sig, signal.SIG_DFL) if start_new_session: os.setsid() try: if env is None: os.execvp(executable, args) else: # Python 3.6 started testing for # bytes values in the env; it also # started encoding strs using # fsencode and using a lower-level # API that takes a list of keys # and values. We don't have access # to that API, so we go the reverse direction. env = {os.fsdecode(k) if isinstance(k, bytes) else k: os.fsdecode(v) if isinstance(v, bytes) else v for k, v in env.items()} os.execvpe(executable, args, env) except OSError as e: e._failed_exec = True raise except: exc_type, exc_value, tb = sys.exc_info() # Save the traceback and attach it to the exception object exc_lines = traceback.format_exception(exc_type, exc_value, tb) exc_value.child_traceback = ''.join(exc_lines) os.write(errpipe_write, pickle.dumps(exc_value)) finally: # Make sure that the process exits no matter what. # The return code does not matter much as it won't be # reported to the application os._exit(1) # Parent self._child_created = True if gc_was_enabled: gc.enable() finally: # be sure the FD is closed no matter what os.close(errpipe_write) # self._devnull is not always defined. devnull_fd = getattr(self, '_devnull', None) if p2cread != -1 and p2cwrite != -1 and p2cread != devnull_fd: os.close(p2cread) if c2pwrite != -1 and c2pread != -1 and c2pwrite != devnull_fd: os.close(c2pwrite) if errwrite != -1 and errread != -1 and errwrite != devnull_fd: os.close(errwrite) if devnull_fd is not None: os.close(devnull_fd) # Prevent a double close of these fds from __init__ on error. self._closed_child_pipe_fds = True # Wait for exec to fail or succeed; possibly raising exception errpipe_read = FileObject(errpipe_read, 'rb') data = errpipe_read.read() finally: try: if hasattr(errpipe_read, 'close'): errpipe_read.close() else: os.close(errpipe_read) except OSError: # Especially on PyPy, we sometimes see the above # `os.close(errpipe_read)` raise an OSError. # It's not entirely clear why, but it happens in # InterprocessSignalTests.test_main sometimes, which must mean # we have some sort of race condition. pass finally: errpipe_read = -1 if data != b"": self.wait() child_exception = pickle.loads(data) for fd in (p2cwrite, c2pread, errread): if fd is not None and fd != -1: os.close(fd) if isinstance(child_exception, OSError): child_exception.filename = executable if hasattr(child_exception, '_failed_chdir'): child_exception.filename = cwd if getattr(child_exception, '_failed_chuser', False): child_exception.filename = None > raise child_exception E OSError: [Errno 8] Exec format error: 'locust' /usr/lib/python3/dist-packages/gevent/subprocess.py:1838: OSError __ StandaloneIntegrationTests.test_no_error_when_same_userclass_in_two_files ___ self = def test_no_error_when_same_userclass_in_two_files(self): with temporary_file(content=MOCK_LOCUSTFILE_CONTENT_A) as file1: MOCK_LOCUSTFILE_CONTENT_C = textwrap.dedent( f""" from {os.path.basename(file1)[:-3]} import TestUser1 """ ) print(MOCK_LOCUSTFILE_CONTENT_C) with temporary_file(content=MOCK_LOCUSTFILE_CONTENT_C) as file2: > proc = subprocess.Popen( ["locust", "-f", f"{file1},{file2}", "-t", "1", "--headless"], stdout=PIPE, stderr=PIPE, text=True ) locust/test/test_main.py:1173: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3/dist-packages/gevent/subprocess.py:808: in __init__ self._execute_child(args, executable, preexec_fn, close_fds, _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = args = ['locust', '-f', '/tmp/tmpe6e4wtf0_locustfile.py,/tmp/tmpplprvst3_locustfile.py', '-t', '1', '--headless'] executable = 'locust', preexec_fn = None, close_fds = True, pass_fds = () cwd = None, env = None, universal_newlines = None, startupinfo = None creationflags = 0, shell = False, p2cread = -1, p2cwrite = -1, c2pread = 11 c2pwrite = 81, errread = 82, errwrite = 83, restore_signals = True, gid = None gids = None, uid = None, umask = -1, start_new_session = False process_group = None def _execute_child(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, universal_newlines, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, restore_signals, gid, gids, uid, umask, start_new_session, process_group): """Execute program (POSIX version)""" if isinstance(args, (str, bytes)): args = [args] elif isinstance(args, PathLike): if shell: raise TypeError('path-like args is not allowed when ' 'shell is true') args = [fsencode(args)] # os.PathLike -> [str] else: args = list(args) if shell: # On Android the default shell is at '/system/bin/sh'. unix_shell = ( '/system/bin/sh' if hasattr(sys, 'getandroidapilevel') else '/bin/sh' ) args = [unix_shell, "-c"] + args if executable: args[0] = executable if executable is None: executable = args[0] self._loop.install_sigchld() # For transferring possible exec failure from child to parent # The first char specifies the exception type: 0 means # OSError, 1 means some other error. errpipe_read, errpipe_write = self.pipe_cloexec() # errpipe_write must not be in the standard io 0, 1, or 2 fd range. low_fds_to_close = [] while errpipe_write < 3: low_fds_to_close.append(errpipe_write) errpipe_write = os.dup(errpipe_write) for low_fd in low_fds_to_close: os.close(low_fd) try: try: gc_was_enabled = gc.isenabled() # Disable gc to avoid bug where gc -> file_dealloc -> # write to stderr -> hang. http://bugs.python.org/issue1336 gc.disable() try: self.pid = fork_and_watch(self._on_child, self._loop, True, fork) except: if gc_was_enabled: gc.enable() raise if self.pid == 0: # Child # In various places on the child side of things, we catch OSError # and add attributes to it that detail where in the process we failed; # like all exceptions until we have exec'd, this exception is pickled # and sent to the parent to raise in the calling process. # The parent uses this to decide how to treat that exception, # adjusting certain information about it as needed. # # Python 3.11.8 --- yes, a minor patch release --- stopped # letting the 'filename' parameter get set in the resulting # exception for many cases. We're not quite interpreting this # the same way the stdlib is, I'm sure, but this makes the stdlib # tests pass. # XXX: Technically we're doing a lot of stuff here that # may not be safe to do before a exec(), depending on the OS. # CPython 3 goes to great lengths to precompute a lot # of this info before the fork and pass it all to C functions that # try hard not to call things like malloc(). (Of course, # CPython 2 pretty much did what we're doing.) try: # Close parent's pipe ends if p2cwrite != -1: os.close(p2cwrite) if c2pread != -1: os.close(c2pread) if errread != -1: os.close(errread) os.close(errpipe_read) # When duping fds, if there arises a situation # where one of the fds is either 0, 1 or 2, it # is possible that it is overwritten (#12607). if c2pwrite == 0: c2pwrite = os.dup(c2pwrite) _set_inheritable(c2pwrite, False) while errwrite in (0, 1): errwrite = os.dup(errwrite) _set_inheritable(errwrite, False) # Dup fds for child def _dup2(existing, desired): # dup2() removes the CLOEXEC flag but # we must do it ourselves if dup2() # would be a no-op (issue #10806). if existing == desired: self._set_cloexec_flag(existing, False) elif existing != -1: os.dup2(existing, desired) try: self._remove_nonblock_flag(desired) except OSError: # Ignore EBADF, it may not actually be # open yet. # Tested beginning in 3.7.0b3 test_subprocess.py pass _dup2(p2cread, 0) _dup2(c2pwrite, 1) _dup2(errwrite, 2) # Close pipe fds. Make sure we don't close the # same fd more than once, or standard fds. if not True: closed = set([None]) for fd in (p2cread, c2pwrite, errwrite): if fd not in closed and fd > 2: os.close(fd) closed.add(fd) # Python 3 (with a working set_inheritable): # We no longer manually close p2cread, # c2pwrite, and errwrite here as # _close_open_fds takes care when it is # not already non-inheritable. if cwd is not None: try: os.chdir(cwd) except OSError as e: e._failed_chdir = True raise # Python 3.9 if umask >= 0: os.umask(umask) # XXX: CPython does _Py_RestoreSignals here. # Then setsid() based on ??? try: if gids: os.setgroups(gids) if gid: os.setregid(gid, gid) if uid: os.setreuid(uid, uid) if process_group is not None: os.setpgid(0, process_group) except OSError as e: e._failed_chuser = True raise if preexec_fn: preexec_fn() # Close all other fds, if asked for. This must be done # after preexec_fn runs. if close_fds: fds_to_keep = set(pass_fds) fds_to_keep.add(errpipe_write) self._close_fds(fds_to_keep, errpipe_write) if restore_signals: # restore the documented signals back to sig_dfl; # not all will be defined on every platform for sig in 'SIGPIPE', 'SIGXFZ', 'SIGXFSZ': sig = getattr(signal, sig, None) if sig is not None: signal.signal(sig, signal.SIG_DFL) if start_new_session: os.setsid() try: if env is None: os.execvp(executable, args) else: # Python 3.6 started testing for # bytes values in the env; it also # started encoding strs using # fsencode and using a lower-level # API that takes a list of keys # and values. We don't have access # to that API, so we go the reverse direction. env = {os.fsdecode(k) if isinstance(k, bytes) else k: os.fsdecode(v) if isinstance(v, bytes) else v for k, v in env.items()} os.execvpe(executable, args, env) except OSError as e: e._failed_exec = True raise except: exc_type, exc_value, tb = sys.exc_info() # Save the traceback and attach it to the exception object exc_lines = traceback.format_exception(exc_type, exc_value, tb) exc_value.child_traceback = ''.join(exc_lines) os.write(errpipe_write, pickle.dumps(exc_value)) finally: # Make sure that the process exits no matter what. # The return code does not matter much as it won't be # reported to the application os._exit(1) # Parent self._child_created = True if gc_was_enabled: gc.enable() finally: # be sure the FD is closed no matter what os.close(errpipe_write) # self._devnull is not always defined. devnull_fd = getattr(self, '_devnull', None) if p2cread != -1 and p2cwrite != -1 and p2cread != devnull_fd: os.close(p2cread) if c2pwrite != -1 and c2pread != -1 and c2pwrite != devnull_fd: os.close(c2pwrite) if errwrite != -1 and errread != -1 and errwrite != devnull_fd: os.close(errwrite) if devnull_fd is not None: os.close(devnull_fd) # Prevent a double close of these fds from __init__ on error. self._closed_child_pipe_fds = True # Wait for exec to fail or succeed; possibly raising exception errpipe_read = FileObject(errpipe_read, 'rb') data = errpipe_read.read() finally: try: if hasattr(errpipe_read, 'close'): errpipe_read.close() else: os.close(errpipe_read) except OSError: # Especially on PyPy, we sometimes see the above # `os.close(errpipe_read)` raise an OSError. # It's not entirely clear why, but it happens in # InterprocessSignalTests.test_main sometimes, which must mean # we have some sort of race condition. pass finally: errpipe_read = -1 if data != b"": self.wait() child_exception = pickle.loads(data) for fd in (p2cwrite, c2pread, errread): if fd is not None and fd != -1: os.close(fd) if isinstance(child_exception, OSError): child_exception.filename = executable if hasattr(child_exception, '_failed_chdir'): child_exception.filename = cwd if getattr(child_exception, '_failed_chuser', False): child_exception.filename = None > raise child_exception E OSError: [Errno 8] Exec format error: 'locust' /usr/lib/python3/dist-packages/gevent/subprocess.py:1838: OSError ----------------------------- Captured stdout call ----------------------------- from tmpe6e4wtf0_locustfile import TestUser1 _____________ StandaloneIntegrationTests.test_percentile_parameter _____________ self = def test_percentile_parameter(self): port = get_free_tcp_port() with temporary_file( content=textwrap.dedent( """ from locust import User, task, constant, events from locust.stats import PERCENTILES_TO_CHART PERCENTILES_TO_CHART[0] = 0.9 PERCENTILES_TO_CHART[1] = 0.4 class TestUser(User): wait_time = constant(3) @task def my_task(self): print("running my_task()") """ ) ) as file_path: > proc = subprocess.Popen( ["locust", "-f", file_path, "--web-port", str(port), "--autostart"], stdout=PIPE, stderr=PIPE, text=True ) locust/test/test_main.py:233: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3/dist-packages/gevent/subprocess.py:808: in __init__ self._execute_child(args, executable, preexec_fn, close_fds, _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = args = ['locust', '-f', '/tmp/tmpmamjrav5_locustfile.py', '--web-port', '59423', '--autostart'] executable = 'locust', preexec_fn = None, close_fds = True, pass_fds = () cwd = None, env = None, universal_newlines = None, startupinfo = None creationflags = 0, shell = False, p2cread = -1, p2cwrite = -1, c2pread = 11 c2pwrite = 81, errread = 82, errwrite = 83, restore_signals = True, gid = None gids = None, uid = None, umask = -1, start_new_session = False process_group = None def _execute_child(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, universal_newlines, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, restore_signals, gid, gids, uid, umask, start_new_session, process_group): """Execute program (POSIX version)""" if isinstance(args, (str, bytes)): args = [args] elif isinstance(args, PathLike): if shell: raise TypeError('path-like args is not allowed when ' 'shell is true') args = [fsencode(args)] # os.PathLike -> [str] else: args = list(args) if shell: # On Android the default shell is at '/system/bin/sh'. unix_shell = ( '/system/bin/sh' if hasattr(sys, 'getandroidapilevel') else '/bin/sh' ) args = [unix_shell, "-c"] + args if executable: args[0] = executable if executable is None: executable = args[0] self._loop.install_sigchld() # For transferring possible exec failure from child to parent # The first char specifies the exception type: 0 means # OSError, 1 means some other error. errpipe_read, errpipe_write = self.pipe_cloexec() # errpipe_write must not be in the standard io 0, 1, or 2 fd range. low_fds_to_close = [] while errpipe_write < 3: low_fds_to_close.append(errpipe_write) errpipe_write = os.dup(errpipe_write) for low_fd in low_fds_to_close: os.close(low_fd) try: try: gc_was_enabled = gc.isenabled() # Disable gc to avoid bug where gc -> file_dealloc -> # write to stderr -> hang. http://bugs.python.org/issue1336 gc.disable() try: self.pid = fork_and_watch(self._on_child, self._loop, True, fork) except: if gc_was_enabled: gc.enable() raise if self.pid == 0: # Child # In various places on the child side of things, we catch OSError # and add attributes to it that detail where in the process we failed; # like all exceptions until we have exec'd, this exception is pickled # and sent to the parent to raise in the calling process. # The parent uses this to decide how to treat that exception, # adjusting certain information about it as needed. # # Python 3.11.8 --- yes, a minor patch release --- stopped # letting the 'filename' parameter get set in the resulting # exception for many cases. We're not quite interpreting this # the same way the stdlib is, I'm sure, but this makes the stdlib # tests pass. # XXX: Technically we're doing a lot of stuff here that # may not be safe to do before a exec(), depending on the OS. # CPython 3 goes to great lengths to precompute a lot # of this info before the fork and pass it all to C functions that # try hard not to call things like malloc(). (Of course, # CPython 2 pretty much did what we're doing.) try: # Close parent's pipe ends if p2cwrite != -1: os.close(p2cwrite) if c2pread != -1: os.close(c2pread) if errread != -1: os.close(errread) os.close(errpipe_read) # When duping fds, if there arises a situation # where one of the fds is either 0, 1 or 2, it # is possible that it is overwritten (#12607). if c2pwrite == 0: c2pwrite = os.dup(c2pwrite) _set_inheritable(c2pwrite, False) while errwrite in (0, 1): errwrite = os.dup(errwrite) _set_inheritable(errwrite, False) # Dup fds for child def _dup2(existing, desired): # dup2() removes the CLOEXEC flag but # we must do it ourselves if dup2() # would be a no-op (issue #10806). if existing == desired: self._set_cloexec_flag(existing, False) elif existing != -1: os.dup2(existing, desired) try: self._remove_nonblock_flag(desired) except OSError: # Ignore EBADF, it may not actually be # open yet. # Tested beginning in 3.7.0b3 test_subprocess.py pass _dup2(p2cread, 0) _dup2(c2pwrite, 1) _dup2(errwrite, 2) # Close pipe fds. Make sure we don't close the # same fd more than once, or standard fds. if not True: closed = set([None]) for fd in (p2cread, c2pwrite, errwrite): if fd not in closed and fd > 2: os.close(fd) closed.add(fd) # Python 3 (with a working set_inheritable): # We no longer manually close p2cread, # c2pwrite, and errwrite here as # _close_open_fds takes care when it is # not already non-inheritable. if cwd is not None: try: os.chdir(cwd) except OSError as e: e._failed_chdir = True raise # Python 3.9 if umask >= 0: os.umask(umask) # XXX: CPython does _Py_RestoreSignals here. # Then setsid() based on ??? try: if gids: os.setgroups(gids) if gid: os.setregid(gid, gid) if uid: os.setreuid(uid, uid) if process_group is not None: os.setpgid(0, process_group) except OSError as e: e._failed_chuser = True raise if preexec_fn: preexec_fn() # Close all other fds, if asked for. This must be done # after preexec_fn runs. if close_fds: fds_to_keep = set(pass_fds) fds_to_keep.add(errpipe_write) self._close_fds(fds_to_keep, errpipe_write) if restore_signals: # restore the documented signals back to sig_dfl; # not all will be defined on every platform for sig in 'SIGPIPE', 'SIGXFZ', 'SIGXFSZ': sig = getattr(signal, sig, None) if sig is not None: signal.signal(sig, signal.SIG_DFL) if start_new_session: os.setsid() try: if env is None: os.execvp(executable, args) else: # Python 3.6 started testing for # bytes values in the env; it also # started encoding strs using # fsencode and using a lower-level # API that takes a list of keys # and values. We don't have access # to that API, so we go the reverse direction. env = {os.fsdecode(k) if isinstance(k, bytes) else k: os.fsdecode(v) if isinstance(v, bytes) else v for k, v in env.items()} os.execvpe(executable, args, env) except OSError as e: e._failed_exec = True raise except: exc_type, exc_value, tb = sys.exc_info() # Save the traceback and attach it to the exception object exc_lines = traceback.format_exception(exc_type, exc_value, tb) exc_value.child_traceback = ''.join(exc_lines) os.write(errpipe_write, pickle.dumps(exc_value)) finally: # Make sure that the process exits no matter what. # The return code does not matter much as it won't be # reported to the application os._exit(1) # Parent self._child_created = True if gc_was_enabled: gc.enable() finally: # be sure the FD is closed no matter what os.close(errpipe_write) # self._devnull is not always defined. devnull_fd = getattr(self, '_devnull', None) if p2cread != -1 and p2cwrite != -1 and p2cread != devnull_fd: os.close(p2cread) if c2pwrite != -1 and c2pread != -1 and c2pwrite != devnull_fd: os.close(c2pwrite) if errwrite != -1 and errread != -1 and errwrite != devnull_fd: os.close(errwrite) if devnull_fd is not None: os.close(devnull_fd) # Prevent a double close of these fds from __init__ on error. self._closed_child_pipe_fds = True # Wait for exec to fail or succeed; possibly raising exception errpipe_read = FileObject(errpipe_read, 'rb') data = errpipe_read.read() finally: try: if hasattr(errpipe_read, 'close'): errpipe_read.close() else: os.close(errpipe_read) except OSError: # Especially on PyPy, we sometimes see the above # `os.close(errpipe_read)` raise an OSError. # It's not entirely clear why, but it happens in # InterprocessSignalTests.test_main sometimes, which must mean # we have some sort of race condition. pass finally: errpipe_read = -1 if data != b"": self.wait() child_exception = pickle.loads(data) for fd in (p2cwrite, c2pread, errread): if fd is not None and fd != -1: os.close(fd) if isinstance(child_exception, OSError): child_exception.filename = executable if hasattr(child_exception, '_failed_chdir'): child_exception.filename = cwd if getattr(child_exception, '_failed_chuser', False): child_exception.filename = None > raise child_exception E OSError: [Errno 8] Exec format error: 'locust' /usr/lib/python3/dist-packages/gevent/subprocess.py:1838: OSError __________ StandaloneIntegrationTests.test_percentiles_to_statistics ___________ self = def test_percentiles_to_statistics(self): port = get_free_tcp_port() with temporary_file( content=textwrap.dedent( """ from locust import User, task, constant, events from locust.stats import PERCENTILES_TO_STATISTICS PERCENTILES_TO_STATISTICS = [0.9, 0.99] class TestUser(User): wait_time = constant(3) @task def my_task(self): print("running my_task()") """ ) ) as file_path: > proc = subprocess.Popen( ["locust", "-f", file_path, "--web-port", str(port), "--autostart"], stdout=PIPE, stderr=PIPE, text=True, ) locust/test/test_main.py:259: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3/dist-packages/gevent/subprocess.py:808: in __init__ self._execute_child(args, executable, preexec_fn, close_fds, _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = args = ['locust', '-f', '/tmp/tmpy5ch6n05_locustfile.py', '--web-port', '47849', '--autostart'] executable = 'locust', preexec_fn = None, close_fds = True, pass_fds = () cwd = None, env = None, universal_newlines = None, startupinfo = None creationflags = 0, shell = False, p2cread = -1, p2cwrite = -1, c2pread = 11 c2pwrite = 81, errread = 82, errwrite = 83, restore_signals = True, gid = None gids = None, uid = None, umask = -1, start_new_session = False process_group = None def _execute_child(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, universal_newlines, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, restore_signals, gid, gids, uid, umask, start_new_session, process_group): """Execute program (POSIX version)""" if isinstance(args, (str, bytes)): args = [args] elif isinstance(args, PathLike): if shell: raise TypeError('path-like args is not allowed when ' 'shell is true') args = [fsencode(args)] # os.PathLike -> [str] else: args = list(args) if shell: # On Android the default shell is at '/system/bin/sh'. unix_shell = ( '/system/bin/sh' if hasattr(sys, 'getandroidapilevel') else '/bin/sh' ) args = [unix_shell, "-c"] + args if executable: args[0] = executable if executable is None: executable = args[0] self._loop.install_sigchld() # For transferring possible exec failure from child to parent # The first char specifies the exception type: 0 means # OSError, 1 means some other error. errpipe_read, errpipe_write = self.pipe_cloexec() # errpipe_write must not be in the standard io 0, 1, or 2 fd range. low_fds_to_close = [] while errpipe_write < 3: low_fds_to_close.append(errpipe_write) errpipe_write = os.dup(errpipe_write) for low_fd in low_fds_to_close: os.close(low_fd) try: try: gc_was_enabled = gc.isenabled() # Disable gc to avoid bug where gc -> file_dealloc -> # write to stderr -> hang. http://bugs.python.org/issue1336 gc.disable() try: self.pid = fork_and_watch(self._on_child, self._loop, True, fork) except: if gc_was_enabled: gc.enable() raise if self.pid == 0: # Child # In various places on the child side of things, we catch OSError # and add attributes to it that detail where in the process we failed; # like all exceptions until we have exec'd, this exception is pickled # and sent to the parent to raise in the calling process. # The parent uses this to decide how to treat that exception, # adjusting certain information about it as needed. # # Python 3.11.8 --- yes, a minor patch release --- stopped # letting the 'filename' parameter get set in the resulting # exception for many cases. We're not quite interpreting this # the same way the stdlib is, I'm sure, but this makes the stdlib # tests pass. # XXX: Technically we're doing a lot of stuff here that # may not be safe to do before a exec(), depending on the OS. # CPython 3 goes to great lengths to precompute a lot # of this info before the fork and pass it all to C functions that # try hard not to call things like malloc(). (Of course, # CPython 2 pretty much did what we're doing.) try: # Close parent's pipe ends if p2cwrite != -1: os.close(p2cwrite) if c2pread != -1: os.close(c2pread) if errread != -1: os.close(errread) os.close(errpipe_read) # When duping fds, if there arises a situation # where one of the fds is either 0, 1 or 2, it # is possible that it is overwritten (#12607). if c2pwrite == 0: c2pwrite = os.dup(c2pwrite) _set_inheritable(c2pwrite, False) while errwrite in (0, 1): errwrite = os.dup(errwrite) _set_inheritable(errwrite, False) # Dup fds for child def _dup2(existing, desired): # dup2() removes the CLOEXEC flag but # we must do it ourselves if dup2() # would be a no-op (issue #10806). if existing == desired: self._set_cloexec_flag(existing, False) elif existing != -1: os.dup2(existing, desired) try: self._remove_nonblock_flag(desired) except OSError: # Ignore EBADF, it may not actually be # open yet. # Tested beginning in 3.7.0b3 test_subprocess.py pass _dup2(p2cread, 0) _dup2(c2pwrite, 1) _dup2(errwrite, 2) # Close pipe fds. Make sure we don't close the # same fd more than once, or standard fds. if not True: closed = set([None]) for fd in (p2cread, c2pwrite, errwrite): if fd not in closed and fd > 2: os.close(fd) closed.add(fd) # Python 3 (with a working set_inheritable): # We no longer manually close p2cread, # c2pwrite, and errwrite here as # _close_open_fds takes care when it is # not already non-inheritable. if cwd is not None: try: os.chdir(cwd) except OSError as e: e._failed_chdir = True raise # Python 3.9 if umask >= 0: os.umask(umask) # XXX: CPython does _Py_RestoreSignals here. # Then setsid() based on ??? try: if gids: os.setgroups(gids) if gid: os.setregid(gid, gid) if uid: os.setreuid(uid, uid) if process_group is not None: os.setpgid(0, process_group) except OSError as e: e._failed_chuser = True raise if preexec_fn: preexec_fn() # Close all other fds, if asked for. This must be done # after preexec_fn runs. if close_fds: fds_to_keep = set(pass_fds) fds_to_keep.add(errpipe_write) self._close_fds(fds_to_keep, errpipe_write) if restore_signals: # restore the documented signals back to sig_dfl; # not all will be defined on every platform for sig in 'SIGPIPE', 'SIGXFZ', 'SIGXFSZ': sig = getattr(signal, sig, None) if sig is not None: signal.signal(sig, signal.SIG_DFL) if start_new_session: os.setsid() try: if env is None: os.execvp(executable, args) else: # Python 3.6 started testing for # bytes values in the env; it also # started encoding strs using # fsencode and using a lower-level # API that takes a list of keys # and values. We don't have access # to that API, so we go the reverse direction. env = {os.fsdecode(k) if isinstance(k, bytes) else k: os.fsdecode(v) if isinstance(v, bytes) else v for k, v in env.items()} os.execvpe(executable, args, env) except OSError as e: e._failed_exec = True raise except: exc_type, exc_value, tb = sys.exc_info() # Save the traceback and attach it to the exception object exc_lines = traceback.format_exception(exc_type, exc_value, tb) exc_value.child_traceback = ''.join(exc_lines) os.write(errpipe_write, pickle.dumps(exc_value)) finally: # Make sure that the process exits no matter what. # The return code does not matter much as it won't be # reported to the application os._exit(1) # Parent self._child_created = True if gc_was_enabled: gc.enable() finally: # be sure the FD is closed no matter what os.close(errpipe_write) # self._devnull is not always defined. devnull_fd = getattr(self, '_devnull', None) if p2cread != -1 and p2cwrite != -1 and p2cread != devnull_fd: os.close(p2cread) if c2pwrite != -1 and c2pread != -1 and c2pwrite != devnull_fd: os.close(c2pwrite) if errwrite != -1 and errread != -1 and errwrite != devnull_fd: os.close(errwrite) if devnull_fd is not None: os.close(devnull_fd) # Prevent a double close of these fds from __init__ on error. self._closed_child_pipe_fds = True # Wait for exec to fail or succeed; possibly raising exception errpipe_read = FileObject(errpipe_read, 'rb') data = errpipe_read.read() finally: try: if hasattr(errpipe_read, 'close'): errpipe_read.close() else: os.close(errpipe_read) except OSError: # Especially on PyPy, we sometimes see the above # `os.close(errpipe_read)` raise an OSError. # It's not entirely clear why, but it happens in # InterprocessSignalTests.test_main sometimes, which must mean # we have some sort of race condition. pass finally: errpipe_read = -1 if data != b"": self.wait() child_exception = pickle.loads(data) for fd in (p2cwrite, c2pread, errread): if fd is not None and fd != -1: os.close(fd) if isinstance(child_exception, OSError): child_exception.filename = executable if hasattr(child_exception, '_failed_chdir'): child_exception.filename = cwd if getattr(child_exception, '_failed_chuser', False): child_exception.filename = None > raise child_exception E OSError: [Errno 8] Exec format error: 'locust' /usr/lib/python3/dist-packages/gevent/subprocess.py:1838: OSError ___ StandaloneIntegrationTests.test_run_autostart_with_multiple_locustfiles ____ self = @unittest.skipIf(os.name == "nt", reason="Signal handling on windows is hard") def test_run_autostart_with_multiple_locustfiles(self): with TemporaryDirectory() as temp_dir: with mock_locustfile(dir=temp_dir): with temporary_file( content=textwrap.dedent( """ from locust import User, task, constant, events class TestUser(User): wait_time = constant(1) @task def my_task(self): print("running my_task()") """ ), dir=temp_dir, ): > proc = subprocess.Popen( [ "locust", "-f", temp_dir, "--autostart", "-u", "2", "--exit-code-on-error", "0", ], stdout=PIPE, stderr=PIPE, text=True, ) locust/test/test_main.py:685: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3/dist-packages/gevent/subprocess.py:808: in __init__ self._execute_child(args, executable, preexec_fn, close_fds, _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = args = ['locust', '-f', '/tmp/tmpbabz8pek', '--autostart', '-u', '2', ...] executable = 'locust', preexec_fn = None, close_fds = True, pass_fds = () cwd = None, env = None, universal_newlines = None, startupinfo = None creationflags = 0, shell = False, p2cread = -1, p2cwrite = -1, c2pread = 11 c2pwrite = 81, errread = 82, errwrite = 83, restore_signals = True, gid = None gids = None, uid = None, umask = -1, start_new_session = False process_group = None def _execute_child(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, universal_newlines, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, restore_signals, gid, gids, uid, umask, start_new_session, process_group): """Execute program (POSIX version)""" if isinstance(args, (str, bytes)): args = [args] elif isinstance(args, PathLike): if shell: raise TypeError('path-like args is not allowed when ' 'shell is true') args = [fsencode(args)] # os.PathLike -> [str] else: args = list(args) if shell: # On Android the default shell is at '/system/bin/sh'. unix_shell = ( '/system/bin/sh' if hasattr(sys, 'getandroidapilevel') else '/bin/sh' ) args = [unix_shell, "-c"] + args if executable: args[0] = executable if executable is None: executable = args[0] self._loop.install_sigchld() # For transferring possible exec failure from child to parent # The first char specifies the exception type: 0 means # OSError, 1 means some other error. errpipe_read, errpipe_write = self.pipe_cloexec() # errpipe_write must not be in the standard io 0, 1, or 2 fd range. low_fds_to_close = [] while errpipe_write < 3: low_fds_to_close.append(errpipe_write) errpipe_write = os.dup(errpipe_write) for low_fd in low_fds_to_close: os.close(low_fd) try: try: gc_was_enabled = gc.isenabled() # Disable gc to avoid bug where gc -> file_dealloc -> # write to stderr -> hang. http://bugs.python.org/issue1336 gc.disable() try: self.pid = fork_and_watch(self._on_child, self._loop, True, fork) except: if gc_was_enabled: gc.enable() raise if self.pid == 0: # Child # In various places on the child side of things, we catch OSError # and add attributes to it that detail where in the process we failed; # like all exceptions until we have exec'd, this exception is pickled # and sent to the parent to raise in the calling process. # The parent uses this to decide how to treat that exception, # adjusting certain information about it as needed. # # Python 3.11.8 --- yes, a minor patch release --- stopped # letting the 'filename' parameter get set in the resulting # exception for many cases. We're not quite interpreting this # the same way the stdlib is, I'm sure, but this makes the stdlib # tests pass. # XXX: Technically we're doing a lot of stuff here that # may not be safe to do before a exec(), depending on the OS. # CPython 3 goes to great lengths to precompute a lot # of this info before the fork and pass it all to C functions that # try hard not to call things like malloc(). (Of course, # CPython 2 pretty much did what we're doing.) try: # Close parent's pipe ends if p2cwrite != -1: os.close(p2cwrite) if c2pread != -1: os.close(c2pread) if errread != -1: os.close(errread) os.close(errpipe_read) # When duping fds, if there arises a situation # where one of the fds is either 0, 1 or 2, it # is possible that it is overwritten (#12607). if c2pwrite == 0: c2pwrite = os.dup(c2pwrite) _set_inheritable(c2pwrite, False) while errwrite in (0, 1): errwrite = os.dup(errwrite) _set_inheritable(errwrite, False) # Dup fds for child def _dup2(existing, desired): # dup2() removes the CLOEXEC flag but # we must do it ourselves if dup2() # would be a no-op (issue #10806). if existing == desired: self._set_cloexec_flag(existing, False) elif existing != -1: os.dup2(existing, desired) try: self._remove_nonblock_flag(desired) except OSError: # Ignore EBADF, it may not actually be # open yet. # Tested beginning in 3.7.0b3 test_subprocess.py pass _dup2(p2cread, 0) _dup2(c2pwrite, 1) _dup2(errwrite, 2) # Close pipe fds. Make sure we don't close the # same fd more than once, or standard fds. if not True: closed = set([None]) for fd in (p2cread, c2pwrite, errwrite): if fd not in closed and fd > 2: os.close(fd) closed.add(fd) # Python 3 (with a working set_inheritable): # We no longer manually close p2cread, # c2pwrite, and errwrite here as # _close_open_fds takes care when it is # not already non-inheritable. if cwd is not None: try: os.chdir(cwd) except OSError as e: e._failed_chdir = True raise # Python 3.9 if umask >= 0: os.umask(umask) # XXX: CPython does _Py_RestoreSignals here. # Then setsid() based on ??? try: if gids: os.setgroups(gids) if gid: os.setregid(gid, gid) if uid: os.setreuid(uid, uid) if process_group is not None: os.setpgid(0, process_group) except OSError as e: e._failed_chuser = True raise if preexec_fn: preexec_fn() # Close all other fds, if asked for. This must be done # after preexec_fn runs. if close_fds: fds_to_keep = set(pass_fds) fds_to_keep.add(errpipe_write) self._close_fds(fds_to_keep, errpipe_write) if restore_signals: # restore the documented signals back to sig_dfl; # not all will be defined on every platform for sig in 'SIGPIPE', 'SIGXFZ', 'SIGXFSZ': sig = getattr(signal, sig, None) if sig is not None: signal.signal(sig, signal.SIG_DFL) if start_new_session: os.setsid() try: if env is None: os.execvp(executable, args) else: # Python 3.6 started testing for # bytes values in the env; it also # started encoding strs using # fsencode and using a lower-level # API that takes a list of keys # and values. We don't have access # to that API, so we go the reverse direction. env = {os.fsdecode(k) if isinstance(k, bytes) else k: os.fsdecode(v) if isinstance(v, bytes) else v for k, v in env.items()} os.execvpe(executable, args, env) except OSError as e: e._failed_exec = True raise except: exc_type, exc_value, tb = sys.exc_info() # Save the traceback and attach it to the exception object exc_lines = traceback.format_exception(exc_type, exc_value, tb) exc_value.child_traceback = ''.join(exc_lines) os.write(errpipe_write, pickle.dumps(exc_value)) finally: # Make sure that the process exits no matter what. # The return code does not matter much as it won't be # reported to the application os._exit(1) # Parent self._child_created = True if gc_was_enabled: gc.enable() finally: # be sure the FD is closed no matter what os.close(errpipe_write) # self._devnull is not always defined. devnull_fd = getattr(self, '_devnull', None) if p2cread != -1 and p2cwrite != -1 and p2cread != devnull_fd: os.close(p2cread) if c2pwrite != -1 and c2pread != -1 and c2pwrite != devnull_fd: os.close(c2pwrite) if errwrite != -1 and errread != -1 and errwrite != devnull_fd: os.close(errwrite) if devnull_fd is not None: os.close(devnull_fd) # Prevent a double close of these fds from __init__ on error. self._closed_child_pipe_fds = True # Wait for exec to fail or succeed; possibly raising exception errpipe_read = FileObject(errpipe_read, 'rb') data = errpipe_read.read() finally: try: if hasattr(errpipe_read, 'close'): errpipe_read.close() else: os.close(errpipe_read) except OSError: # Especially on PyPy, we sometimes see the above # `os.close(errpipe_read)` raise an OSError. # It's not entirely clear why, but it happens in # InterprocessSignalTests.test_main sometimes, which must mean # we have some sort of race condition. pass finally: errpipe_read = -1 if data != b"": self.wait() child_exception = pickle.loads(data) for fd in (p2cwrite, c2pread, errread): if fd is not None and fd != -1: os.close(fd) if isinstance(child_exception, OSError): child_exception.filename = executable if hasattr(child_exception, '_failed_chdir'): child_exception.filename = cwd if getattr(child_exception, '_failed_chuser', False): child_exception.filename = None > raise child_exception E OSError: [Errno 8] Exec format error: 'locust' /usr/lib/python3/dist-packages/gevent/subprocess.py:1838: OSError ____ StandaloneIntegrationTests.test_run_headless_with_multiple_locustfiles ____ self = @unittest.skipIf(os.name == "nt", reason="Signal handling on windows is hard") def test_run_headless_with_multiple_locustfiles(self): with TemporaryDirectory() as temp_dir: with mock_locustfile(dir=temp_dir): with temporary_file( content=textwrap.dedent( """ from locust import User, task, constant, events class TestUser(User): wait_time = constant(1) @task def my_task(self): print("running my_task()") """ ), dir=temp_dir, ): > proc = subprocess.Popen( [ "locust", "-f", temp_dir, "--headless", "-u", "2", "--exit-code-on-error", "0", ], stdout=PIPE, stderr=PIPE, text=True, ) locust/test/test_main.py:461: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3/dist-packages/gevent/subprocess.py:808: in __init__ self._execute_child(args, executable, preexec_fn, close_fds, _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = args = ['locust', '-f', '/tmp/tmpsrwusnjr', '--headless', '-u', '2', ...] executable = 'locust', preexec_fn = None, close_fds = True, pass_fds = () cwd = None, env = None, universal_newlines = None, startupinfo = None creationflags = 0, shell = False, p2cread = -1, p2cwrite = -1, c2pread = 11 c2pwrite = 81, errread = 82, errwrite = 83, restore_signals = True, gid = None gids = None, uid = None, umask = -1, start_new_session = False process_group = None def _execute_child(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, universal_newlines, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, restore_signals, gid, gids, uid, umask, start_new_session, process_group): """Execute program (POSIX version)""" if isinstance(args, (str, bytes)): args = [args] elif isinstance(args, PathLike): if shell: raise TypeError('path-like args is not allowed when ' 'shell is true') args = [fsencode(args)] # os.PathLike -> [str] else: args = list(args) if shell: # On Android the default shell is at '/system/bin/sh'. unix_shell = ( '/system/bin/sh' if hasattr(sys, 'getandroidapilevel') else '/bin/sh' ) args = [unix_shell, "-c"] + args if executable: args[0] = executable if executable is None: executable = args[0] self._loop.install_sigchld() # For transferring possible exec failure from child to parent # The first char specifies the exception type: 0 means # OSError, 1 means some other error. errpipe_read, errpipe_write = self.pipe_cloexec() # errpipe_write must not be in the standard io 0, 1, or 2 fd range. low_fds_to_close = [] while errpipe_write < 3: low_fds_to_close.append(errpipe_write) errpipe_write = os.dup(errpipe_write) for low_fd in low_fds_to_close: os.close(low_fd) try: try: gc_was_enabled = gc.isenabled() # Disable gc to avoid bug where gc -> file_dealloc -> # write to stderr -> hang. http://bugs.python.org/issue1336 gc.disable() try: self.pid = fork_and_watch(self._on_child, self._loop, True, fork) except: if gc_was_enabled: gc.enable() raise if self.pid == 0: # Child # In various places on the child side of things, we catch OSError # and add attributes to it that detail where in the process we failed; # like all exceptions until we have exec'd, this exception is pickled # and sent to the parent to raise in the calling process. # The parent uses this to decide how to treat that exception, # adjusting certain information about it as needed. # # Python 3.11.8 --- yes, a minor patch release --- stopped # letting the 'filename' parameter get set in the resulting # exception for many cases. We're not quite interpreting this # the same way the stdlib is, I'm sure, but this makes the stdlib # tests pass. # XXX: Technically we're doing a lot of stuff here that # may not be safe to do before a exec(), depending on the OS. # CPython 3 goes to great lengths to precompute a lot # of this info before the fork and pass it all to C functions that # try hard not to call things like malloc(). (Of course, # CPython 2 pretty much did what we're doing.) try: # Close parent's pipe ends if p2cwrite != -1: os.close(p2cwrite) if c2pread != -1: os.close(c2pread) if errread != -1: os.close(errread) os.close(errpipe_read) # When duping fds, if there arises a situation # where one of the fds is either 0, 1 or 2, it # is possible that it is overwritten (#12607). if c2pwrite == 0: c2pwrite = os.dup(c2pwrite) _set_inheritable(c2pwrite, False) while errwrite in (0, 1): errwrite = os.dup(errwrite) _set_inheritable(errwrite, False) # Dup fds for child def _dup2(existing, desired): # dup2() removes the CLOEXEC flag but # we must do it ourselves if dup2() # would be a no-op (issue #10806). if existing == desired: self._set_cloexec_flag(existing, False) elif existing != -1: os.dup2(existing, desired) try: self._remove_nonblock_flag(desired) except OSError: # Ignore EBADF, it may not actually be # open yet. # Tested beginning in 3.7.0b3 test_subprocess.py pass _dup2(p2cread, 0) _dup2(c2pwrite, 1) _dup2(errwrite, 2) # Close pipe fds. Make sure we don't close the # same fd more than once, or standard fds. if not True: closed = set([None]) for fd in (p2cread, c2pwrite, errwrite): if fd not in closed and fd > 2: os.close(fd) closed.add(fd) # Python 3 (with a working set_inheritable): # We no longer manually close p2cread, # c2pwrite, and errwrite here as # _close_open_fds takes care when it is # not already non-inheritable. if cwd is not None: try: os.chdir(cwd) except OSError as e: e._failed_chdir = True raise # Python 3.9 if umask >= 0: os.umask(umask) # XXX: CPython does _Py_RestoreSignals here. # Then setsid() based on ??? try: if gids: os.setgroups(gids) if gid: os.setregid(gid, gid) if uid: os.setreuid(uid, uid) if process_group is not None: os.setpgid(0, process_group) except OSError as e: e._failed_chuser = True raise if preexec_fn: preexec_fn() # Close all other fds, if asked for. This must be done # after preexec_fn runs. if close_fds: fds_to_keep = set(pass_fds) fds_to_keep.add(errpipe_write) self._close_fds(fds_to_keep, errpipe_write) if restore_signals: # restore the documented signals back to sig_dfl; # not all will be defined on every platform for sig in 'SIGPIPE', 'SIGXFZ', 'SIGXFSZ': sig = getattr(signal, sig, None) if sig is not None: signal.signal(sig, signal.SIG_DFL) if start_new_session: os.setsid() try: if env is None: os.execvp(executable, args) else: # Python 3.6 started testing for # bytes values in the env; it also # started encoding strs using # fsencode and using a lower-level # API that takes a list of keys # and values. We don't have access # to that API, so we go the reverse direction. env = {os.fsdecode(k) if isinstance(k, bytes) else k: os.fsdecode(v) if isinstance(v, bytes) else v for k, v in env.items()} os.execvpe(executable, args, env) except OSError as e: e._failed_exec = True raise except: exc_type, exc_value, tb = sys.exc_info() # Save the traceback and attach it to the exception object exc_lines = traceback.format_exception(exc_type, exc_value, tb) exc_value.child_traceback = ''.join(exc_lines) os.write(errpipe_write, pickle.dumps(exc_value)) finally: # Make sure that the process exits no matter what. # The return code does not matter much as it won't be # reported to the application os._exit(1) # Parent self._child_created = True if gc_was_enabled: gc.enable() finally: # be sure the FD is closed no matter what os.close(errpipe_write) # self._devnull is not always defined. devnull_fd = getattr(self, '_devnull', None) if p2cread != -1 and p2cwrite != -1 and p2cread != devnull_fd: os.close(p2cread) if c2pwrite != -1 and c2pread != -1 and c2pwrite != devnull_fd: os.close(c2pwrite) if errwrite != -1 and errread != -1 and errwrite != devnull_fd: os.close(errwrite) if devnull_fd is not None: os.close(devnull_fd) # Prevent a double close of these fds from __init__ on error. self._closed_child_pipe_fds = True # Wait for exec to fail or succeed; possibly raising exception errpipe_read = FileObject(errpipe_read, 'rb') data = errpipe_read.read() finally: try: if hasattr(errpipe_read, 'close'): errpipe_read.close() else: os.close(errpipe_read) except OSError: # Especially on PyPy, we sometimes see the above # `os.close(errpipe_read)` raise an OSError. # It's not entirely clear why, but it happens in # InterprocessSignalTests.test_main sometimes, which must mean # we have some sort of race condition. pass finally: errpipe_read = -1 if data != b"": self.wait() child_exception = pickle.loads(data) for fd in (p2cwrite, c2pread, errread): if fd is not None and fd != -1: os.close(fd) if isinstance(child_exception, OSError): child_exception.filename = executable if hasattr(child_exception, '_failed_chdir'): child_exception.filename = cwd if getattr(child_exception, '_failed_chuser', False): child_exception.filename = None > raise child_exception E OSError: [Errno 8] Exec format error: 'locust' /usr/lib/python3/dist-packages/gevent/subprocess.py:1838: OSError _ StandaloneIntegrationTests.test_run_headless_with_multiple_locustfiles_with_shape _ self = def test_run_headless_with_multiple_locustfiles_with_shape(self): content = textwrap.dedent( """ from locust import User, task, between class TestUser2(User): wait_time = between(2, 4) @task def my_task(self): print("running my_task() again") """ ) with mock_locustfile(content=content) as mocked1: with temporary_file( content=textwrap.dedent( """ from locust import User, task, between, LoadTestShape class LoadTestShape(LoadTestShape): def tick(self): run_time = self.get_run_time() if run_time < 2: return (10, 1) return None class TestUser(User): wait_time = between(2, 4) @task def my_task(self): print("running my_task()") """ ) ) as mocked2: > proc = subprocess.Popen( [ "locust", "-f", f"{mocked1.file_path},{mocked2}", "--host", "https://test.com/", "--headless", "--exit-code-on-error", "0", ], stdout=PIPE, stderr=PIPE, text=True, ) locust/test/test_main.py:565: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3/dist-packages/gevent/subprocess.py:808: in __init__ self._execute_child(args, executable, preexec_fn, close_fds, _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = args = ['locust', '-f', '/build/reproducible-path/locust-2.24.0/locust/test/mock_locustfile_1715256383_9318342_55539.py,/tmp/tmpl7zk43c7_locustfile.py', '--host', 'https://test.com/', '--headless', ...] executable = 'locust', preexec_fn = None, close_fds = True, pass_fds = () cwd = None, env = None, universal_newlines = None, startupinfo = None creationflags = 0, shell = False, p2cread = -1, p2cwrite = -1, c2pread = 11 c2pwrite = 81, errread = 82, errwrite = 83, restore_signals = True, gid = None gids = None, uid = None, umask = -1, start_new_session = False process_group = None def _execute_child(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, universal_newlines, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, restore_signals, gid, gids, uid, umask, start_new_session, process_group): """Execute program (POSIX version)""" if isinstance(args, (str, bytes)): args = [args] elif isinstance(args, PathLike): if shell: raise TypeError('path-like args is not allowed when ' 'shell is true') args = [fsencode(args)] # os.PathLike -> [str] else: args = list(args) if shell: # On Android the default shell is at '/system/bin/sh'. unix_shell = ( '/system/bin/sh' if hasattr(sys, 'getandroidapilevel') else '/bin/sh' ) args = [unix_shell, "-c"] + args if executable: args[0] = executable if executable is None: executable = args[0] self._loop.install_sigchld() # For transferring possible exec failure from child to parent # The first char specifies the exception type: 0 means # OSError, 1 means some other error. errpipe_read, errpipe_write = self.pipe_cloexec() # errpipe_write must not be in the standard io 0, 1, or 2 fd range. low_fds_to_close = [] while errpipe_write < 3: low_fds_to_close.append(errpipe_write) errpipe_write = os.dup(errpipe_write) for low_fd in low_fds_to_close: os.close(low_fd) try: try: gc_was_enabled = gc.isenabled() # Disable gc to avoid bug where gc -> file_dealloc -> # write to stderr -> hang. http://bugs.python.org/issue1336 gc.disable() try: self.pid = fork_and_watch(self._on_child, self._loop, True, fork) except: if gc_was_enabled: gc.enable() raise if self.pid == 0: # Child # In various places on the child side of things, we catch OSError # and add attributes to it that detail where in the process we failed; # like all exceptions until we have exec'd, this exception is pickled # and sent to the parent to raise in the calling process. # The parent uses this to decide how to treat that exception, # adjusting certain information about it as needed. # # Python 3.11.8 --- yes, a minor patch release --- stopped # letting the 'filename' parameter get set in the resulting # exception for many cases. We're not quite interpreting this # the same way the stdlib is, I'm sure, but this makes the stdlib # tests pass. # XXX: Technically we're doing a lot of stuff here that # may not be safe to do before a exec(), depending on the OS. # CPython 3 goes to great lengths to precompute a lot # of this info before the fork and pass it all to C functions that # try hard not to call things like malloc(). (Of course, # CPython 2 pretty much did what we're doing.) try: # Close parent's pipe ends if p2cwrite != -1: os.close(p2cwrite) if c2pread != -1: os.close(c2pread) if errread != -1: os.close(errread) os.close(errpipe_read) # When duping fds, if there arises a situation # where one of the fds is either 0, 1 or 2, it # is possible that it is overwritten (#12607). if c2pwrite == 0: c2pwrite = os.dup(c2pwrite) _set_inheritable(c2pwrite, False) while errwrite in (0, 1): errwrite = os.dup(errwrite) _set_inheritable(errwrite, False) # Dup fds for child def _dup2(existing, desired): # dup2() removes the CLOEXEC flag but # we must do it ourselves if dup2() # would be a no-op (issue #10806). if existing == desired: self._set_cloexec_flag(existing, False) elif existing != -1: os.dup2(existing, desired) try: self._remove_nonblock_flag(desired) except OSError: # Ignore EBADF, it may not actually be # open yet. # Tested beginning in 3.7.0b3 test_subprocess.py pass _dup2(p2cread, 0) _dup2(c2pwrite, 1) _dup2(errwrite, 2) # Close pipe fds. Make sure we don't close the # same fd more than once, or standard fds. if not True: closed = set([None]) for fd in (p2cread, c2pwrite, errwrite): if fd not in closed and fd > 2: os.close(fd) closed.add(fd) # Python 3 (with a working set_inheritable): # We no longer manually close p2cread, # c2pwrite, and errwrite here as # _close_open_fds takes care when it is # not already non-inheritable. if cwd is not None: try: os.chdir(cwd) except OSError as e: e._failed_chdir = True raise # Python 3.9 if umask >= 0: os.umask(umask) # XXX: CPython does _Py_RestoreSignals here. # Then setsid() based on ??? try: if gids: os.setgroups(gids) if gid: os.setregid(gid, gid) if uid: os.setreuid(uid, uid) if process_group is not None: os.setpgid(0, process_group) except OSError as e: e._failed_chuser = True raise if preexec_fn: preexec_fn() # Close all other fds, if asked for. This must be done # after preexec_fn runs. if close_fds: fds_to_keep = set(pass_fds) fds_to_keep.add(errpipe_write) self._close_fds(fds_to_keep, errpipe_write) if restore_signals: # restore the documented signals back to sig_dfl; # not all will be defined on every platform for sig in 'SIGPIPE', 'SIGXFZ', 'SIGXFSZ': sig = getattr(signal, sig, None) if sig is not None: signal.signal(sig, signal.SIG_DFL) if start_new_session: os.setsid() try: if env is None: os.execvp(executable, args) else: # Python 3.6 started testing for # bytes values in the env; it also # started encoding strs using # fsencode and using a lower-level # API that takes a list of keys # and values. We don't have access # to that API, so we go the reverse direction. env = {os.fsdecode(k) if isinstance(k, bytes) else k: os.fsdecode(v) if isinstance(v, bytes) else v for k, v in env.items()} os.execvpe(executable, args, env) except OSError as e: e._failed_exec = True raise except: exc_type, exc_value, tb = sys.exc_info() # Save the traceback and attach it to the exception object exc_lines = traceback.format_exception(exc_type, exc_value, tb) exc_value.child_traceback = ''.join(exc_lines) os.write(errpipe_write, pickle.dumps(exc_value)) finally: # Make sure that the process exits no matter what. # The return code does not matter much as it won't be # reported to the application os._exit(1) # Parent self._child_created = True if gc_was_enabled: gc.enable() finally: # be sure the FD is closed no matter what os.close(errpipe_write) # self._devnull is not always defined. devnull_fd = getattr(self, '_devnull', None) if p2cread != -1 and p2cwrite != -1 and p2cread != devnull_fd: os.close(p2cread) if c2pwrite != -1 and c2pread != -1 and c2pwrite != devnull_fd: os.close(c2pwrite) if errwrite != -1 and errread != -1 and errwrite != devnull_fd: os.close(errwrite) if devnull_fd is not None: os.close(devnull_fd) # Prevent a double close of these fds from __init__ on error. self._closed_child_pipe_fds = True # Wait for exec to fail or succeed; possibly raising exception errpipe_read = FileObject(errpipe_read, 'rb') data = errpipe_read.read() finally: try: if hasattr(errpipe_read, 'close'): errpipe_read.close() else: os.close(errpipe_read) except OSError: # Especially on PyPy, we sometimes see the above # `os.close(errpipe_read)` raise an OSError. # It's not entirely clear why, but it happens in # InterprocessSignalTests.test_main sometimes, which must mean # we have some sort of race condition. pass finally: errpipe_read = -1 if data != b"": self.wait() child_exception = pickle.loads(data) for fd in (p2cwrite, c2pread, errread): if fd is not None and fd != -1: os.close(fd) if isinstance(child_exception, OSError): child_exception.filename = executable if hasattr(child_exception, '_failed_chdir'): child_exception.filename = cwd if getattr(child_exception, '_failed_chuser', False): child_exception.filename = None > raise child_exception E OSError: [Errno 8] Exec format error: 'locust' /usr/lib/python3/dist-packages/gevent/subprocess.py:1838: OSError __________ StandaloneIntegrationTests.test_run_with_userclass_picker ___________ self = def test_run_with_userclass_picker(self): with temporary_file(content=MOCK_LOCUSTFILE_CONTENT_A) as file1: with temporary_file(content=MOCK_LOCUSTFILE_CONTENT_B) as file2: > proc = subprocess.Popen( ["locust", "-f", f"{file1},{file2}", "--class-picker"], stdout=PIPE, stderr=PIPE, text=True, ) locust/test/test_main.py:1130: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3/dist-packages/gevent/subprocess.py:808: in __init__ self._execute_child(args, executable, preexec_fn, close_fds, _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = args = ['locust', '-f', '/tmp/tmp5watsfmo_locustfile.py,/tmp/tmpn1gogv5f_locustfile.py', '--class-picker'] executable = 'locust', preexec_fn = None, close_fds = True, pass_fds = () cwd = None, env = None, universal_newlines = None, startupinfo = None creationflags = 0, shell = False, p2cread = -1, p2cwrite = -1, c2pread = 11 c2pwrite = 81, errread = 82, errwrite = 83, restore_signals = True, gid = None gids = None, uid = None, umask = -1, start_new_session = False process_group = None def _execute_child(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, universal_newlines, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, restore_signals, gid, gids, uid, umask, start_new_session, process_group): """Execute program (POSIX version)""" if isinstance(args, (str, bytes)): args = [args] elif isinstance(args, PathLike): if shell: raise TypeError('path-like args is not allowed when ' 'shell is true') args = [fsencode(args)] # os.PathLike -> [str] else: args = list(args) if shell: # On Android the default shell is at '/system/bin/sh'. unix_shell = ( '/system/bin/sh' if hasattr(sys, 'getandroidapilevel') else '/bin/sh' ) args = [unix_shell, "-c"] + args if executable: args[0] = executable if executable is None: executable = args[0] self._loop.install_sigchld() # For transferring possible exec failure from child to parent # The first char specifies the exception type: 0 means # OSError, 1 means some other error. errpipe_read, errpipe_write = self.pipe_cloexec() # errpipe_write must not be in the standard io 0, 1, or 2 fd range. low_fds_to_close = [] while errpipe_write < 3: low_fds_to_close.append(errpipe_write) errpipe_write = os.dup(errpipe_write) for low_fd in low_fds_to_close: os.close(low_fd) try: try: gc_was_enabled = gc.isenabled() # Disable gc to avoid bug where gc -> file_dealloc -> # write to stderr -> hang. http://bugs.python.org/issue1336 gc.disable() try: self.pid = fork_and_watch(self._on_child, self._loop, True, fork) except: if gc_was_enabled: gc.enable() raise if self.pid == 0: # Child # In various places on the child side of things, we catch OSError # and add attributes to it that detail where in the process we failed; # like all exceptions until we have exec'd, this exception is pickled # and sent to the parent to raise in the calling process. # The parent uses this to decide how to treat that exception, # adjusting certain information about it as needed. # # Python 3.11.8 --- yes, a minor patch release --- stopped # letting the 'filename' parameter get set in the resulting # exception for many cases. We're not quite interpreting this # the same way the stdlib is, I'm sure, but this makes the stdlib # tests pass. # XXX: Technically we're doing a lot of stuff here that # may not be safe to do before a exec(), depending on the OS. # CPython 3 goes to great lengths to precompute a lot # of this info before the fork and pass it all to C functions that # try hard not to call things like malloc(). (Of course, # CPython 2 pretty much did what we're doing.) try: # Close parent's pipe ends if p2cwrite != -1: os.close(p2cwrite) if c2pread != -1: os.close(c2pread) if errread != -1: os.close(errread) os.close(errpipe_read) # When duping fds, if there arises a situation # where one of the fds is either 0, 1 or 2, it # is possible that it is overwritten (#12607). if c2pwrite == 0: c2pwrite = os.dup(c2pwrite) _set_inheritable(c2pwrite, False) while errwrite in (0, 1): errwrite = os.dup(errwrite) _set_inheritable(errwrite, False) # Dup fds for child def _dup2(existing, desired): # dup2() removes the CLOEXEC flag but # we must do it ourselves if dup2() # would be a no-op (issue #10806). if existing == desired: self._set_cloexec_flag(existing, False) elif existing != -1: os.dup2(existing, desired) try: self._remove_nonblock_flag(desired) except OSError: # Ignore EBADF, it may not actually be # open yet. # Tested beginning in 3.7.0b3 test_subprocess.py pass _dup2(p2cread, 0) _dup2(c2pwrite, 1) _dup2(errwrite, 2) # Close pipe fds. Make sure we don't close the # same fd more than once, or standard fds. if not True: closed = set([None]) for fd in (p2cread, c2pwrite, errwrite): if fd not in closed and fd > 2: os.close(fd) closed.add(fd) # Python 3 (with a working set_inheritable): # We no longer manually close p2cread, # c2pwrite, and errwrite here as # _close_open_fds takes care when it is # not already non-inheritable. if cwd is not None: try: os.chdir(cwd) except OSError as e: e._failed_chdir = True raise # Python 3.9 if umask >= 0: os.umask(umask) # XXX: CPython does _Py_RestoreSignals here. # Then setsid() based on ??? try: if gids: os.setgroups(gids) if gid: os.setregid(gid, gid) if uid: os.setreuid(uid, uid) if process_group is not None: os.setpgid(0, process_group) except OSError as e: e._failed_chuser = True raise if preexec_fn: preexec_fn() # Close all other fds, if asked for. This must be done # after preexec_fn runs. if close_fds: fds_to_keep = set(pass_fds) fds_to_keep.add(errpipe_write) self._close_fds(fds_to_keep, errpipe_write) if restore_signals: # restore the documented signals back to sig_dfl; # not all will be defined on every platform for sig in 'SIGPIPE', 'SIGXFZ', 'SIGXFSZ': sig = getattr(signal, sig, None) if sig is not None: signal.signal(sig, signal.SIG_DFL) if start_new_session: os.setsid() try: if env is None: os.execvp(executable, args) else: # Python 3.6 started testing for # bytes values in the env; it also # started encoding strs using # fsencode and using a lower-level # API that takes a list of keys # and values. We don't have access # to that API, so we go the reverse direction. env = {os.fsdecode(k) if isinstance(k, bytes) else k: os.fsdecode(v) if isinstance(v, bytes) else v for k, v in env.items()} os.execvpe(executable, args, env) except OSError as e: e._failed_exec = True raise except: exc_type, exc_value, tb = sys.exc_info() # Save the traceback and attach it to the exception object exc_lines = traceback.format_exception(exc_type, exc_value, tb) exc_value.child_traceback = ''.join(exc_lines) os.write(errpipe_write, pickle.dumps(exc_value)) finally: # Make sure that the process exits no matter what. # The return code does not matter much as it won't be # reported to the application os._exit(1) # Parent self._child_created = True if gc_was_enabled: gc.enable() finally: # be sure the FD is closed no matter what os.close(errpipe_write) # self._devnull is not always defined. devnull_fd = getattr(self, '_devnull', None) if p2cread != -1 and p2cwrite != -1 and p2cread != devnull_fd: os.close(p2cread) if c2pwrite != -1 and c2pread != -1 and c2pwrite != devnull_fd: os.close(c2pwrite) if errwrite != -1 and errread != -1 and errwrite != devnull_fd: os.close(errwrite) if devnull_fd is not None: os.close(devnull_fd) # Prevent a double close of these fds from __init__ on error. self._closed_child_pipe_fds = True # Wait for exec to fail or succeed; possibly raising exception errpipe_read = FileObject(errpipe_read, 'rb') data = errpipe_read.read() finally: try: if hasattr(errpipe_read, 'close'): errpipe_read.close() else: os.close(errpipe_read) except OSError: # Especially on PyPy, we sometimes see the above # `os.close(errpipe_read)` raise an OSError. # It's not entirely clear why, but it happens in # InterprocessSignalTests.test_main sometimes, which must mean # we have some sort of race condition. pass finally: errpipe_read = -1 if data != b"": self.wait() child_exception = pickle.loads(data) for fd in (p2cwrite, c2pread, errread): if fd is not None and fd != -1: os.close(fd) if isinstance(child_exception, OSError): child_exception.filename = executable if hasattr(child_exception, '_failed_chdir'): child_exception.filename = cwd if getattr(child_exception, '_failed_chuser', False): child_exception.filename = None > raise child_exception E OSError: [Errno 8] Exec format error: 'locust' /usr/lib/python3/dist-packages/gevent/subprocess.py:1838: OSError _____ StandaloneIntegrationTests.test_shape_class_log_disabled_parameters ______ self = def test_shape_class_log_disabled_parameters(self): content = MOCK_LOCUSTFILE_CONTENT + textwrap.dedent( """ from locust import LoadTestShape class TestShape(LoadTestShape): def tick(self): return None """ ) with mock_locustfile(content=content) as mocked: > out = self.assert_run( [ "locust", "--headless", "-f", mocked.file_path, "--exit-code-on-error=0", "--users=1", "--spawn-rate=1", ] ) locust/test/test_main.py:1252: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ locust/test/test_main.py:65: in assert_run out = subprocess.run(cmd, capture_output=True, text=True, timeout=timeout) /usr/lib/python3/dist-packages/gevent/subprocess.py:2001: in run with Popen(*popenargs, **kwargs) as process: /usr/lib/python3/dist-packages/gevent/subprocess.py:808: in __init__ self._execute_child(args, executable, preexec_fn, close_fds, _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = args = ['locust', '--headless', '-f', '/build/reproducible-path/locust-2.24.0/locust/test/mock_locustfile_1715256384_4744835_91247.py', '--exit-code-on-error=0', '--users=1', ...] executable = 'locust', preexec_fn = None, close_fds = True, pass_fds = () cwd = None, env = None, universal_newlines = None, startupinfo = None creationflags = 0, shell = False, p2cread = -1, p2cwrite = -1, c2pread = 11 c2pwrite = 81, errread = 82, errwrite = 83, restore_signals = True, gid = None gids = None, uid = None, umask = -1, start_new_session = False process_group = None def _execute_child(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, universal_newlines, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, restore_signals, gid, gids, uid, umask, start_new_session, process_group): """Execute program (POSIX version)""" if isinstance(args, (str, bytes)): args = [args] elif isinstance(args, PathLike): if shell: raise TypeError('path-like args is not allowed when ' 'shell is true') args = [fsencode(args)] # os.PathLike -> [str] else: args = list(args) if shell: # On Android the default shell is at '/system/bin/sh'. unix_shell = ( '/system/bin/sh' if hasattr(sys, 'getandroidapilevel') else '/bin/sh' ) args = [unix_shell, "-c"] + args if executable: args[0] = executable if executable is None: executable = args[0] self._loop.install_sigchld() # For transferring possible exec failure from child to parent # The first char specifies the exception type: 0 means # OSError, 1 means some other error. errpipe_read, errpipe_write = self.pipe_cloexec() # errpipe_write must not be in the standard io 0, 1, or 2 fd range. low_fds_to_close = [] while errpipe_write < 3: low_fds_to_close.append(errpipe_write) errpipe_write = os.dup(errpipe_write) for low_fd in low_fds_to_close: os.close(low_fd) try: try: gc_was_enabled = gc.isenabled() # Disable gc to avoid bug where gc -> file_dealloc -> # write to stderr -> hang. http://bugs.python.org/issue1336 gc.disable() try: self.pid = fork_and_watch(self._on_child, self._loop, True, fork) except: if gc_was_enabled: gc.enable() raise if self.pid == 0: # Child # In various places on the child side of things, we catch OSError # and add attributes to it that detail where in the process we failed; # like all exceptions until we have exec'd, this exception is pickled # and sent to the parent to raise in the calling process. # The parent uses this to decide how to treat that exception, # adjusting certain information about it as needed. # # Python 3.11.8 --- yes, a minor patch release --- stopped # letting the 'filename' parameter get set in the resulting # exception for many cases. We're not quite interpreting this # the same way the stdlib is, I'm sure, but this makes the stdlib # tests pass. # XXX: Technically we're doing a lot of stuff here that # may not be safe to do before a exec(), depending on the OS. # CPython 3 goes to great lengths to precompute a lot # of this info before the fork and pass it all to C functions that # try hard not to call things like malloc(). (Of course, # CPython 2 pretty much did what we're doing.) try: # Close parent's pipe ends if p2cwrite != -1: os.close(p2cwrite) if c2pread != -1: os.close(c2pread) if errread != -1: os.close(errread) os.close(errpipe_read) # When duping fds, if there arises a situation # where one of the fds is either 0, 1 or 2, it # is possible that it is overwritten (#12607). if c2pwrite == 0: c2pwrite = os.dup(c2pwrite) _set_inheritable(c2pwrite, False) while errwrite in (0, 1): errwrite = os.dup(errwrite) _set_inheritable(errwrite, False) # Dup fds for child def _dup2(existing, desired): # dup2() removes the CLOEXEC flag but # we must do it ourselves if dup2() # would be a no-op (issue #10806). if existing == desired: self._set_cloexec_flag(existing, False) elif existing != -1: os.dup2(existing, desired) try: self._remove_nonblock_flag(desired) except OSError: # Ignore EBADF, it may not actually be # open yet. # Tested beginning in 3.7.0b3 test_subprocess.py pass _dup2(p2cread, 0) _dup2(c2pwrite, 1) _dup2(errwrite, 2) # Close pipe fds. Make sure we don't close the # same fd more than once, or standard fds. if not True: closed = set([None]) for fd in (p2cread, c2pwrite, errwrite): if fd not in closed and fd > 2: os.close(fd) closed.add(fd) # Python 3 (with a working set_inheritable): # We no longer manually close p2cread, # c2pwrite, and errwrite here as # _close_open_fds takes care when it is # not already non-inheritable. if cwd is not None: try: os.chdir(cwd) except OSError as e: e._failed_chdir = True raise # Python 3.9 if umask >= 0: os.umask(umask) # XXX: CPython does _Py_RestoreSignals here. # Then setsid() based on ??? try: if gids: os.setgroups(gids) if gid: os.setregid(gid, gid) if uid: os.setreuid(uid, uid) if process_group is not None: os.setpgid(0, process_group) except OSError as e: e._failed_chuser = True raise if preexec_fn: preexec_fn() # Close all other fds, if asked for. This must be done # after preexec_fn runs. if close_fds: fds_to_keep = set(pass_fds) fds_to_keep.add(errpipe_write) self._close_fds(fds_to_keep, errpipe_write) if restore_signals: # restore the documented signals back to sig_dfl; # not all will be defined on every platform for sig in 'SIGPIPE', 'SIGXFZ', 'SIGXFSZ': sig = getattr(signal, sig, None) if sig is not None: signal.signal(sig, signal.SIG_DFL) if start_new_session: os.setsid() try: if env is None: os.execvp(executable, args) else: # Python 3.6 started testing for # bytes values in the env; it also # started encoding strs using # fsencode and using a lower-level # API that takes a list of keys # and values. We don't have access # to that API, so we go the reverse direction. env = {os.fsdecode(k) if isinstance(k, bytes) else k: os.fsdecode(v) if isinstance(v, bytes) else v for k, v in env.items()} os.execvpe(executable, args, env) except OSError as e: e._failed_exec = True raise except: exc_type, exc_value, tb = sys.exc_info() # Save the traceback and attach it to the exception object exc_lines = traceback.format_exception(exc_type, exc_value, tb) exc_value.child_traceback = ''.join(exc_lines) os.write(errpipe_write, pickle.dumps(exc_value)) finally: # Make sure that the process exits no matter what. # The return code does not matter much as it won't be # reported to the application os._exit(1) # Parent self._child_created = True if gc_was_enabled: gc.enable() finally: # be sure the FD is closed no matter what os.close(errpipe_write) # self._devnull is not always defined. devnull_fd = getattr(self, '_devnull', None) if p2cread != -1 and p2cwrite != -1 and p2cread != devnull_fd: os.close(p2cread) if c2pwrite != -1 and c2pread != -1 and c2pwrite != devnull_fd: os.close(c2pwrite) if errwrite != -1 and errread != -1 and errwrite != devnull_fd: os.close(errwrite) if devnull_fd is not None: os.close(devnull_fd) # Prevent a double close of these fds from __init__ on error. self._closed_child_pipe_fds = True # Wait for exec to fail or succeed; possibly raising exception errpipe_read = FileObject(errpipe_read, 'rb') data = errpipe_read.read() finally: try: if hasattr(errpipe_read, 'close'): errpipe_read.close() else: os.close(errpipe_read) except OSError: # Especially on PyPy, we sometimes see the above # `os.close(errpipe_read)` raise an OSError. # It's not entirely clear why, but it happens in # InterprocessSignalTests.test_main sometimes, which must mean # we have some sort of race condition. pass finally: errpipe_read = -1 if data != b"": self.wait() child_exception = pickle.loads(data) for fd in (p2cwrite, c2pread, errread): if fd is not None and fd != -1: os.close(fd) if isinstance(child_exception, OSError): child_exception.filename = executable if hasattr(child_exception, '_failed_chdir'): child_exception.filename = cwd if getattr(child_exception, '_failed_chuser', False): child_exception.filename = None > raise child_exception E OSError: [Errno 8] Exec format error: 'locust' /usr/lib/python3/dist-packages/gevent/subprocess.py:1838: OSError _____ StandaloneIntegrationTests.test_shape_class_with_use_common_options ______ self = def test_shape_class_with_use_common_options(self): content = MOCK_LOCUSTFILE_CONTENT + textwrap.dedent( """ from locust import LoadTestShape class TestShape(LoadTestShape): use_common_options = True def tick(self): return None """ ) with mock_locustfile(content=content) as mocked: > out = self.assert_run( [ "locust", "-f", mocked.file_path, "--run-time=1s", "--users=1", "--spawn-rate=1", "--headless", "--exit-code-on-error=0", ] ) locust/test/test_main.py:1280: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ locust/test/test_main.py:65: in assert_run out = subprocess.run(cmd, capture_output=True, text=True, timeout=timeout) /usr/lib/python3/dist-packages/gevent/subprocess.py:2001: in run with Popen(*popenargs, **kwargs) as process: /usr/lib/python3/dist-packages/gevent/subprocess.py:808: in __init__ self._execute_child(args, executable, preexec_fn, close_fds, _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = args = ['locust', '-f', '/build/reproducible-path/locust-2.24.0/locust/test/mock_locustfile_1715256384_714806_59015.py', '--run-time=1s', '--users=1', '--spawn-rate=1', ...] executable = 'locust', preexec_fn = None, close_fds = True, pass_fds = () cwd = None, env = None, universal_newlines = None, startupinfo = None creationflags = 0, shell = False, p2cread = -1, p2cwrite = -1, c2pread = 11 c2pwrite = 81, errread = 82, errwrite = 83, restore_signals = True, gid = None gids = None, uid = None, umask = -1, start_new_session = False process_group = None def _execute_child(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, universal_newlines, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, restore_signals, gid, gids, uid, umask, start_new_session, process_group): """Execute program (POSIX version)""" if isinstance(args, (str, bytes)): args = [args] elif isinstance(args, PathLike): if shell: raise TypeError('path-like args is not allowed when ' 'shell is true') args = [fsencode(args)] # os.PathLike -> [str] else: args = list(args) if shell: # On Android the default shell is at '/system/bin/sh'. unix_shell = ( '/system/bin/sh' if hasattr(sys, 'getandroidapilevel') else '/bin/sh' ) args = [unix_shell, "-c"] + args if executable: args[0] = executable if executable is None: executable = args[0] self._loop.install_sigchld() # For transferring possible exec failure from child to parent # The first char specifies the exception type: 0 means # OSError, 1 means some other error. errpipe_read, errpipe_write = self.pipe_cloexec() # errpipe_write must not be in the standard io 0, 1, or 2 fd range. low_fds_to_close = [] while errpipe_write < 3: low_fds_to_close.append(errpipe_write) errpipe_write = os.dup(errpipe_write) for low_fd in low_fds_to_close: os.close(low_fd) try: try: gc_was_enabled = gc.isenabled() # Disable gc to avoid bug where gc -> file_dealloc -> # write to stderr -> hang. http://bugs.python.org/issue1336 gc.disable() try: self.pid = fork_and_watch(self._on_child, self._loop, True, fork) except: if gc_was_enabled: gc.enable() raise if self.pid == 0: # Child # In various places on the child side of things, we catch OSError # and add attributes to it that detail where in the process we failed; # like all exceptions until we have exec'd, this exception is pickled # and sent to the parent to raise in the calling process. # The parent uses this to decide how to treat that exception, # adjusting certain information about it as needed. # # Python 3.11.8 --- yes, a minor patch release --- stopped # letting the 'filename' parameter get set in the resulting # exception for many cases. We're not quite interpreting this # the same way the stdlib is, I'm sure, but this makes the stdlib # tests pass. # XXX: Technically we're doing a lot of stuff here that # may not be safe to do before a exec(), depending on the OS. # CPython 3 goes to great lengths to precompute a lot # of this info before the fork and pass it all to C functions that # try hard not to call things like malloc(). (Of course, # CPython 2 pretty much did what we're doing.) try: # Close parent's pipe ends if p2cwrite != -1: os.close(p2cwrite) if c2pread != -1: os.close(c2pread) if errread != -1: os.close(errread) os.close(errpipe_read) # When duping fds, if there arises a situation # where one of the fds is either 0, 1 or 2, it # is possible that it is overwritten (#12607). if c2pwrite == 0: c2pwrite = os.dup(c2pwrite) _set_inheritable(c2pwrite, False) while errwrite in (0, 1): errwrite = os.dup(errwrite) _set_inheritable(errwrite, False) # Dup fds for child def _dup2(existing, desired): # dup2() removes the CLOEXEC flag but # we must do it ourselves if dup2() # would be a no-op (issue #10806). if existing == desired: self._set_cloexec_flag(existing, False) elif existing != -1: os.dup2(existing, desired) try: self._remove_nonblock_flag(desired) except OSError: # Ignore EBADF, it may not actually be # open yet. # Tested beginning in 3.7.0b3 test_subprocess.py pass _dup2(p2cread, 0) _dup2(c2pwrite, 1) _dup2(errwrite, 2) # Close pipe fds. Make sure we don't close the # same fd more than once, or standard fds. if not True: closed = set([None]) for fd in (p2cread, c2pwrite, errwrite): if fd not in closed and fd > 2: os.close(fd) closed.add(fd) # Python 3 (with a working set_inheritable): # We no longer manually close p2cread, # c2pwrite, and errwrite here as # _close_open_fds takes care when it is # not already non-inheritable. if cwd is not None: try: os.chdir(cwd) except OSError as e: e._failed_chdir = True raise # Python 3.9 if umask >= 0: os.umask(umask) # XXX: CPython does _Py_RestoreSignals here. # Then setsid() based on ??? try: if gids: os.setgroups(gids) if gid: os.setregid(gid, gid) if uid: os.setreuid(uid, uid) if process_group is not None: os.setpgid(0, process_group) except OSError as e: e._failed_chuser = True raise if preexec_fn: preexec_fn() # Close all other fds, if asked for. This must be done # after preexec_fn runs. if close_fds: fds_to_keep = set(pass_fds) fds_to_keep.add(errpipe_write) self._close_fds(fds_to_keep, errpipe_write) if restore_signals: # restore the documented signals back to sig_dfl; # not all will be defined on every platform for sig in 'SIGPIPE', 'SIGXFZ', 'SIGXFSZ': sig = getattr(signal, sig, None) if sig is not None: signal.signal(sig, signal.SIG_DFL) if start_new_session: os.setsid() try: if env is None: os.execvp(executable, args) else: # Python 3.6 started testing for # bytes values in the env; it also # started encoding strs using # fsencode and using a lower-level # API that takes a list of keys # and values. We don't have access # to that API, so we go the reverse direction. env = {os.fsdecode(k) if isinstance(k, bytes) else k: os.fsdecode(v) if isinstance(v, bytes) else v for k, v in env.items()} os.execvpe(executable, args, env) except OSError as e: e._failed_exec = True raise except: exc_type, exc_value, tb = sys.exc_info() # Save the traceback and attach it to the exception object exc_lines = traceback.format_exception(exc_type, exc_value, tb) exc_value.child_traceback = ''.join(exc_lines) os.write(errpipe_write, pickle.dumps(exc_value)) finally: # Make sure that the process exits no matter what. # The return code does not matter much as it won't be # reported to the application os._exit(1) # Parent self._child_created = True if gc_was_enabled: gc.enable() finally: # be sure the FD is closed no matter what os.close(errpipe_write) # self._devnull is not always defined. devnull_fd = getattr(self, '_devnull', None) if p2cread != -1 and p2cwrite != -1 and p2cread != devnull_fd: os.close(p2cread) if c2pwrite != -1 and c2pread != -1 and c2pwrite != devnull_fd: os.close(c2pwrite) if errwrite != -1 and errread != -1 and errwrite != devnull_fd: os.close(errwrite) if devnull_fd is not None: os.close(devnull_fd) # Prevent a double close of these fds from __init__ on error. self._closed_child_pipe_fds = True # Wait for exec to fail or succeed; possibly raising exception errpipe_read = FileObject(errpipe_read, 'rb') data = errpipe_read.read() finally: try: if hasattr(errpipe_read, 'close'): errpipe_read.close() else: os.close(errpipe_read) except OSError: # Especially on PyPy, we sometimes see the above # `os.close(errpipe_read)` raise an OSError. # It's not entirely clear why, but it happens in # InterprocessSignalTests.test_main sometimes, which must mean # we have some sort of race condition. pass finally: errpipe_read = -1 if data != b"": self.wait() child_exception = pickle.loads(data) for fd in (p2cwrite, c2pread, errread): if fd is not None and fd != -1: os.close(fd) if isinstance(child_exception, OSError): child_exception.filename = executable if hasattr(child_exception, '_failed_chdir'): child_exception.filename = cwd if getattr(child_exception, '_failed_chuser', False): child_exception.filename = None > raise child_exception E OSError: [Errno 8] Exec format error: 'locust' /usr/lib/python3/dist-packages/gevent/subprocess.py:1838: OSError ___ StandaloneIntegrationTests.test_spawing_with_fixed_multiple_locustfiles ____ self = def test_spawing_with_fixed_multiple_locustfiles(self): with mock_locustfile(content=MOCK_LOCUSTFILE_CONTENT_A) as mocked1: with mock_locustfile(content=MOCK_LOCUSTFILE_CONTENT_B) as mocked2: proc = subprocess.Popen( " ".join( [ "locust", "-f", f"{mocked1.file_path},{mocked2.file_path}", "--headless", "--run-time", "5s", "-u", "10", "-r", "10", "--loglevel", "INFO", ] ), stderr=STDOUT, stdout=PIPE, shell=True, text=True, ) output = proc.communicate()[0] > self.assertIn("Ramping to 10 users at a rate of 10.00 per second", output) E AssertionError: 'Ramping to 10 users at a rate of 10.00 per second' not found in '/build/reproducible-path/locust-2.24.0/debian/locust: line 2: from: command not found\n/build/reproducible-path/locust-2.24.0/debian/locust: line 5: syntax error: unexpected end of file\n' locust/test/test_main.py:1022: AssertionError _____________ StandaloneIntegrationTests.test_spawning_with_fixed ______________ self = def test_spawning_with_fixed(self): LOCUSTFILE_CONTENT = textwrap.dedent( """ from locust import User, task, constant class User1(User): fixed_count = 2 wait_time = constant(1) @task def t(self): print("Test task is running") class User2(User): wait_time = constant(1) @task def t(self): print("Test task is running") class User3(User): wait_time = constant(1) @task def t(self): print("Test task is running") """ ) with mock_locustfile(content=LOCUSTFILE_CONTENT) as mocked: proc = subprocess.Popen( " ".join( [ "locust", "-f", mocked.file_path, "--headless", "--run-time", "5s", "-u", "10", "-r", "10", "--loglevel", "INFO", ] ), stderr=STDOUT, stdout=PIPE, shell=True, text=True, ) output = proc.communicate()[0] > self.assertIn("Ramping to 10 users at a rate of 10.00 per second", output) E AssertionError: 'Ramping to 10 users at a rate of 10.00 per second' not found in '/build/reproducible-path/locust-2.24.0/debian/locust: line 2: from: command not found\n/build/reproducible-path/locust-2.24.0/debian/locust: line 5: syntax error: unexpected end of file\n' locust/test/test_main.py:987: AssertionError _________________ StandaloneIntegrationTests.test_web_options __________________ self = @unittest.skipIf(platform.system() == "Darwin", reason="Messy on macOS on GH") @unittest.skipIf(os.name == "nt", reason="Signal handling on windows is hard") def test_web_options(self): port = get_free_tcp_port() if platform.system() != "Darwin": # MacOS only sets up the loopback interface for 127.0.0.1 and not for 127.*.*.*, so we cant test this with mock_locustfile() as mocked: > proc = subprocess.Popen( ["locust", "-f", mocked.file_path, "--web-host", "127.0.0.2", "--web-port", str(port)], stdout=PIPE, stderr=PIPE, ) locust/test/test_main.py:838: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3/dist-packages/gevent/subprocess.py:808: in __init__ self._execute_child(args, executable, preexec_fn, close_fds, _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = args = ['locust', '-f', '/build/reproducible-path/locust-2.24.0/locust/test/mock_locustfile_1715256385_4120898_65187.py', '--web-host', '127.0.0.2', '--web-port', ...] executable = 'locust', preexec_fn = None, close_fds = True, pass_fds = () cwd = None, env = None, universal_newlines = None, startupinfo = None creationflags = 0, shell = False, p2cread = -1, p2cwrite = -1, c2pread = 11 c2pwrite = 81, errread = 82, errwrite = 83, restore_signals = True, gid = None gids = None, uid = None, umask = -1, start_new_session = False process_group = None def _execute_child(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, universal_newlines, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, restore_signals, gid, gids, uid, umask, start_new_session, process_group): """Execute program (POSIX version)""" if isinstance(args, (str, bytes)): args = [args] elif isinstance(args, PathLike): if shell: raise TypeError('path-like args is not allowed when ' 'shell is true') args = [fsencode(args)] # os.PathLike -> [str] else: args = list(args) if shell: # On Android the default shell is at '/system/bin/sh'. unix_shell = ( '/system/bin/sh' if hasattr(sys, 'getandroidapilevel') else '/bin/sh' ) args = [unix_shell, "-c"] + args if executable: args[0] = executable if executable is None: executable = args[0] self._loop.install_sigchld() # For transferring possible exec failure from child to parent # The first char specifies the exception type: 0 means # OSError, 1 means some other error. errpipe_read, errpipe_write = self.pipe_cloexec() # errpipe_write must not be in the standard io 0, 1, or 2 fd range. low_fds_to_close = [] while errpipe_write < 3: low_fds_to_close.append(errpipe_write) errpipe_write = os.dup(errpipe_write) for low_fd in low_fds_to_close: os.close(low_fd) try: try: gc_was_enabled = gc.isenabled() # Disable gc to avoid bug where gc -> file_dealloc -> # write to stderr -> hang. http://bugs.python.org/issue1336 gc.disable() try: self.pid = fork_and_watch(self._on_child, self._loop, True, fork) except: if gc_was_enabled: gc.enable() raise if self.pid == 0: # Child # In various places on the child side of things, we catch OSError # and add attributes to it that detail where in the process we failed; # like all exceptions until we have exec'd, this exception is pickled # and sent to the parent to raise in the calling process. # The parent uses this to decide how to treat that exception, # adjusting certain information about it as needed. # # Python 3.11.8 --- yes, a minor patch release --- stopped # letting the 'filename' parameter get set in the resulting # exception for many cases. We're not quite interpreting this # the same way the stdlib is, I'm sure, but this makes the stdlib # tests pass. # XXX: Technically we're doing a lot of stuff here that # may not be safe to do before a exec(), depending on the OS. # CPython 3 goes to great lengths to precompute a lot # of this info before the fork and pass it all to C functions that # try hard not to call things like malloc(). (Of course, # CPython 2 pretty much did what we're doing.) try: # Close parent's pipe ends if p2cwrite != -1: os.close(p2cwrite) if c2pread != -1: os.close(c2pread) if errread != -1: os.close(errread) os.close(errpipe_read) # When duping fds, if there arises a situation # where one of the fds is either 0, 1 or 2, it # is possible that it is overwritten (#12607). if c2pwrite == 0: c2pwrite = os.dup(c2pwrite) _set_inheritable(c2pwrite, False) while errwrite in (0, 1): errwrite = os.dup(errwrite) _set_inheritable(errwrite, False) # Dup fds for child def _dup2(existing, desired): # dup2() removes the CLOEXEC flag but # we must do it ourselves if dup2() # would be a no-op (issue #10806). if existing == desired: self._set_cloexec_flag(existing, False) elif existing != -1: os.dup2(existing, desired) try: self._remove_nonblock_flag(desired) except OSError: # Ignore EBADF, it may not actually be # open yet. # Tested beginning in 3.7.0b3 test_subprocess.py pass _dup2(p2cread, 0) _dup2(c2pwrite, 1) _dup2(errwrite, 2) # Close pipe fds. Make sure we don't close the # same fd more than once, or standard fds. if not True: closed = set([None]) for fd in (p2cread, c2pwrite, errwrite): if fd not in closed and fd > 2: os.close(fd) closed.add(fd) # Python 3 (with a working set_inheritable): # We no longer manually close p2cread, # c2pwrite, and errwrite here as # _close_open_fds takes care when it is # not already non-inheritable. if cwd is not None: try: os.chdir(cwd) except OSError as e: e._failed_chdir = True raise # Python 3.9 if umask >= 0: os.umask(umask) # XXX: CPython does _Py_RestoreSignals here. # Then setsid() based on ??? try: if gids: os.setgroups(gids) if gid: os.setregid(gid, gid) if uid: os.setreuid(uid, uid) if process_group is not None: os.setpgid(0, process_group) except OSError as e: e._failed_chuser = True raise if preexec_fn: preexec_fn() # Close all other fds, if asked for. This must be done # after preexec_fn runs. if close_fds: fds_to_keep = set(pass_fds) fds_to_keep.add(errpipe_write) self._close_fds(fds_to_keep, errpipe_write) if restore_signals: # restore the documented signals back to sig_dfl; # not all will be defined on every platform for sig in 'SIGPIPE', 'SIGXFZ', 'SIGXFSZ': sig = getattr(signal, sig, None) if sig is not None: signal.signal(sig, signal.SIG_DFL) if start_new_session: os.setsid() try: if env is None: os.execvp(executable, args) else: # Python 3.6 started testing for # bytes values in the env; it also # started encoding strs using # fsencode and using a lower-level # API that takes a list of keys # and values. We don't have access # to that API, so we go the reverse direction. env = {os.fsdecode(k) if isinstance(k, bytes) else k: os.fsdecode(v) if isinstance(v, bytes) else v for k, v in env.items()} os.execvpe(executable, args, env) except OSError as e: e._failed_exec = True raise except: exc_type, exc_value, tb = sys.exc_info() # Save the traceback and attach it to the exception object exc_lines = traceback.format_exception(exc_type, exc_value, tb) exc_value.child_traceback = ''.join(exc_lines) os.write(errpipe_write, pickle.dumps(exc_value)) finally: # Make sure that the process exits no matter what. # The return code does not matter much as it won't be # reported to the application os._exit(1) # Parent self._child_created = True if gc_was_enabled: gc.enable() finally: # be sure the FD is closed no matter what os.close(errpipe_write) # self._devnull is not always defined. devnull_fd = getattr(self, '_devnull', None) if p2cread != -1 and p2cwrite != -1 and p2cread != devnull_fd: os.close(p2cread) if c2pwrite != -1 and c2pread != -1 and c2pwrite != devnull_fd: os.close(c2pwrite) if errwrite != -1 and errread != -1 and errwrite != devnull_fd: os.close(errwrite) if devnull_fd is not None: os.close(devnull_fd) # Prevent a double close of these fds from __init__ on error. self._closed_child_pipe_fds = True # Wait for exec to fail or succeed; possibly raising exception errpipe_read = FileObject(errpipe_read, 'rb') data = errpipe_read.read() finally: try: if hasattr(errpipe_read, 'close'): errpipe_read.close() else: os.close(errpipe_read) except OSError: # Especially on PyPy, we sometimes see the above # `os.close(errpipe_read)` raise an OSError. # It's not entirely clear why, but it happens in # InterprocessSignalTests.test_main sometimes, which must mean # we have some sort of race condition. pass finally: errpipe_read = -1 if data != b"": self.wait() child_exception = pickle.loads(data) for fd in (p2cwrite, c2pread, errread): if fd is not None and fd != -1: os.close(fd) if isinstance(child_exception, OSError): child_exception.filename = executable if hasattr(child_exception, '_failed_chdir'): child_exception.filename = cwd if getattr(child_exception, '_failed_chuser', False): child_exception.filename = None > raise child_exception E OSError: [Errno 8] Exec format error: 'locust' /usr/lib/python3/dist-packages/gevent/subprocess.py:1838: OSError __________________ StandaloneIntegrationTests.test_webserver ___________________ self = @unittest.skipIf(os.name == "nt", reason="Signal handling on windows is hard") def test_webserver(self): with temporary_file( content=textwrap.dedent( """ from locust import User, task, constant, events class TestUser(User): wait_time = constant(3) @task def my_task(self): print("running my_task()") """ ) ) as file_path: > proc = subprocess.Popen(["locust", "-f", file_path], stdout=PIPE, stderr=PIPE, text=True) locust/test/test_main.py:206: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3/dist-packages/gevent/subprocess.py:808: in __init__ self._execute_child(args, executable, preexec_fn, close_fds, _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = args = ['locust', '-f', '/tmp/tmps41hcs_n_locustfile.py'], executable = 'locust' preexec_fn = None, close_fds = True, pass_fds = (), cwd = None, env = None universal_newlines = None, startupinfo = None, creationflags = 0, shell = False p2cread = -1, p2cwrite = -1, c2pread = 11, c2pwrite = 81, errread = 82 errwrite = 83, restore_signals = True, gid = None, gids = None, uid = None umask = -1, start_new_session = False, process_group = None def _execute_child(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, universal_newlines, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, restore_signals, gid, gids, uid, umask, start_new_session, process_group): """Execute program (POSIX version)""" if isinstance(args, (str, bytes)): args = [args] elif isinstance(args, PathLike): if shell: raise TypeError('path-like args is not allowed when ' 'shell is true') args = [fsencode(args)] # os.PathLike -> [str] else: args = list(args) if shell: # On Android the default shell is at '/system/bin/sh'. unix_shell = ( '/system/bin/sh' if hasattr(sys, 'getandroidapilevel') else '/bin/sh' ) args = [unix_shell, "-c"] + args if executable: args[0] = executable if executable is None: executable = args[0] self._loop.install_sigchld() # For transferring possible exec failure from child to parent # The first char specifies the exception type: 0 means # OSError, 1 means some other error. errpipe_read, errpipe_write = self.pipe_cloexec() # errpipe_write must not be in the standard io 0, 1, or 2 fd range. low_fds_to_close = [] while errpipe_write < 3: low_fds_to_close.append(errpipe_write) errpipe_write = os.dup(errpipe_write) for low_fd in low_fds_to_close: os.close(low_fd) try: try: gc_was_enabled = gc.isenabled() # Disable gc to avoid bug where gc -> file_dealloc -> # write to stderr -> hang. http://bugs.python.org/issue1336 gc.disable() try: self.pid = fork_and_watch(self._on_child, self._loop, True, fork) except: if gc_was_enabled: gc.enable() raise if self.pid == 0: # Child # In various places on the child side of things, we catch OSError # and add attributes to it that detail where in the process we failed; # like all exceptions until we have exec'd, this exception is pickled # and sent to the parent to raise in the calling process. # The parent uses this to decide how to treat that exception, # adjusting certain information about it as needed. # # Python 3.11.8 --- yes, a minor patch release --- stopped # letting the 'filename' parameter get set in the resulting # exception for many cases. We're not quite interpreting this # the same way the stdlib is, I'm sure, but this makes the stdlib # tests pass. # XXX: Technically we're doing a lot of stuff here that # may not be safe to do before a exec(), depending on the OS. # CPython 3 goes to great lengths to precompute a lot # of this info before the fork and pass it all to C functions that # try hard not to call things like malloc(). (Of course, # CPython 2 pretty much did what we're doing.) try: # Close parent's pipe ends if p2cwrite != -1: os.close(p2cwrite) if c2pread != -1: os.close(c2pread) if errread != -1: os.close(errread) os.close(errpipe_read) # When duping fds, if there arises a situation # where one of the fds is either 0, 1 or 2, it # is possible that it is overwritten (#12607). if c2pwrite == 0: c2pwrite = os.dup(c2pwrite) _set_inheritable(c2pwrite, False) while errwrite in (0, 1): errwrite = os.dup(errwrite) _set_inheritable(errwrite, False) # Dup fds for child def _dup2(existing, desired): # dup2() removes the CLOEXEC flag but # we must do it ourselves if dup2() # would be a no-op (issue #10806). if existing == desired: self._set_cloexec_flag(existing, False) elif existing != -1: os.dup2(existing, desired) try: self._remove_nonblock_flag(desired) except OSError: # Ignore EBADF, it may not actually be # open yet. # Tested beginning in 3.7.0b3 test_subprocess.py pass _dup2(p2cread, 0) _dup2(c2pwrite, 1) _dup2(errwrite, 2) # Close pipe fds. Make sure we don't close the # same fd more than once, or standard fds. if not True: closed = set([None]) for fd in (p2cread, c2pwrite, errwrite): if fd not in closed and fd > 2: os.close(fd) closed.add(fd) # Python 3 (with a working set_inheritable): # We no longer manually close p2cread, # c2pwrite, and errwrite here as # _close_open_fds takes care when it is # not already non-inheritable. if cwd is not None: try: os.chdir(cwd) except OSError as e: e._failed_chdir = True raise # Python 3.9 if umask >= 0: os.umask(umask) # XXX: CPython does _Py_RestoreSignals here. # Then setsid() based on ??? try: if gids: os.setgroups(gids) if gid: os.setregid(gid, gid) if uid: os.setreuid(uid, uid) if process_group is not None: os.setpgid(0, process_group) except OSError as e: e._failed_chuser = True raise if preexec_fn: preexec_fn() # Close all other fds, if asked for. This must be done # after preexec_fn runs. if close_fds: fds_to_keep = set(pass_fds) fds_to_keep.add(errpipe_write) self._close_fds(fds_to_keep, errpipe_write) if restore_signals: # restore the documented signals back to sig_dfl; # not all will be defined on every platform for sig in 'SIGPIPE', 'SIGXFZ', 'SIGXFSZ': sig = getattr(signal, sig, None) if sig is not None: signal.signal(sig, signal.SIG_DFL) if start_new_session: os.setsid() try: if env is None: os.execvp(executable, args) else: # Python 3.6 started testing for # bytes values in the env; it also # started encoding strs using # fsencode and using a lower-level # API that takes a list of keys # and values. We don't have access # to that API, so we go the reverse direction. env = {os.fsdecode(k) if isinstance(k, bytes) else k: os.fsdecode(v) if isinstance(v, bytes) else v for k, v in env.items()} os.execvpe(executable, args, env) except OSError as e: e._failed_exec = True raise except: exc_type, exc_value, tb = sys.exc_info() # Save the traceback and attach it to the exception object exc_lines = traceback.format_exception(exc_type, exc_value, tb) exc_value.child_traceback = ''.join(exc_lines) os.write(errpipe_write, pickle.dumps(exc_value)) finally: # Make sure that the process exits no matter what. # The return code does not matter much as it won't be # reported to the application os._exit(1) # Parent self._child_created = True if gc_was_enabled: gc.enable() finally: # be sure the FD is closed no matter what os.close(errpipe_write) # self._devnull is not always defined. devnull_fd = getattr(self, '_devnull', None) if p2cread != -1 and p2cwrite != -1 and p2cread != devnull_fd: os.close(p2cread) if c2pwrite != -1 and c2pread != -1 and c2pwrite != devnull_fd: os.close(c2pwrite) if errwrite != -1 and errread != -1 and errwrite != devnull_fd: os.close(errwrite) if devnull_fd is not None: os.close(devnull_fd) # Prevent a double close of these fds from __init__ on error. self._closed_child_pipe_fds = True # Wait for exec to fail or succeed; possibly raising exception errpipe_read = FileObject(errpipe_read, 'rb') data = errpipe_read.read() finally: try: if hasattr(errpipe_read, 'close'): errpipe_read.close() else: os.close(errpipe_read) except OSError: # Especially on PyPy, we sometimes see the above # `os.close(errpipe_read)` raise an OSError. # It's not entirely clear why, but it happens in # InterprocessSignalTests.test_main sometimes, which must mean # we have some sort of race condition. pass finally: errpipe_read = -1 if data != b"": self.wait() child_exception = pickle.loads(data) for fd in (p2cwrite, c2pread, errread): if fd is not None and fd != -1: os.close(fd) if isinstance(child_exception, OSError): child_exception.filename = executable if hasattr(child_exception, '_failed_chdir'): child_exception.filename = cwd if getattr(child_exception, '_failed_chuser', False): child_exception.filename = None > raise child_exception E OSError: [Errno 8] Exec format error: 'locust' /usr/lib/python3/dist-packages/gevent/subprocess.py:1838: OSError ________ StandaloneIntegrationTests.test_webserver_multiple_locustfiles ________ self = @unittest.skipIf(os.name == "nt", reason="Signal handling on windows is hard") def test_webserver_multiple_locustfiles(self): with mock_locustfile(content=MOCK_LOCUSTFILE_CONTENT_A) as mocked1: with mock_locustfile(content=MOCK_LOCUSTFILE_CONTENT_B) as mocked2: > proc = subprocess.Popen( ["locust", "-f", f"{mocked1.file_path},{mocked2.file_path}"], stdout=PIPE, stderr=PIPE, text=True ) locust/test/test_main.py:297: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3/dist-packages/gevent/subprocess.py:808: in __init__ self._execute_child(args, executable, preexec_fn, close_fds, _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = args = ['locust', '-f', '/build/reproducible-path/locust-2.24.0/locust/test/mock_locustfile_1715256385_8957891_49628.py,/build/reproducible-path/locust-2.24.0/locust/test/mock_locustfile_1715256385_895939_64928.py'] executable = 'locust', preexec_fn = None, close_fds = True, pass_fds = () cwd = None, env = None, universal_newlines = None, startupinfo = None creationflags = 0, shell = False, p2cread = -1, p2cwrite = -1, c2pread = 11 c2pwrite = 81, errread = 82, errwrite = 83, restore_signals = True, gid = None gids = None, uid = None, umask = -1, start_new_session = False process_group = None def _execute_child(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, universal_newlines, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, restore_signals, gid, gids, uid, umask, start_new_session, process_group): """Execute program (POSIX version)""" if isinstance(args, (str, bytes)): args = [args] elif isinstance(args, PathLike): if shell: raise TypeError('path-like args is not allowed when ' 'shell is true') args = [fsencode(args)] # os.PathLike -> [str] else: args = list(args) if shell: # On Android the default shell is at '/system/bin/sh'. unix_shell = ( '/system/bin/sh' if hasattr(sys, 'getandroidapilevel') else '/bin/sh' ) args = [unix_shell, "-c"] + args if executable: args[0] = executable if executable is None: executable = args[0] self._loop.install_sigchld() # For transferring possible exec failure from child to parent # The first char specifies the exception type: 0 means # OSError, 1 means some other error. errpipe_read, errpipe_write = self.pipe_cloexec() # errpipe_write must not be in the standard io 0, 1, or 2 fd range. low_fds_to_close = [] while errpipe_write < 3: low_fds_to_close.append(errpipe_write) errpipe_write = os.dup(errpipe_write) for low_fd in low_fds_to_close: os.close(low_fd) try: try: gc_was_enabled = gc.isenabled() # Disable gc to avoid bug where gc -> file_dealloc -> # write to stderr -> hang. http://bugs.python.org/issue1336 gc.disable() try: self.pid = fork_and_watch(self._on_child, self._loop, True, fork) except: if gc_was_enabled: gc.enable() raise if self.pid == 0: # Child # In various places on the child side of things, we catch OSError # and add attributes to it that detail where in the process we failed; # like all exceptions until we have exec'd, this exception is pickled # and sent to the parent to raise in the calling process. # The parent uses this to decide how to treat that exception, # adjusting certain information about it as needed. # # Python 3.11.8 --- yes, a minor patch release --- stopped # letting the 'filename' parameter get set in the resulting # exception for many cases. We're not quite interpreting this # the same way the stdlib is, I'm sure, but this makes the stdlib # tests pass. # XXX: Technically we're doing a lot of stuff here that # may not be safe to do before a exec(), depending on the OS. # CPython 3 goes to great lengths to precompute a lot # of this info before the fork and pass it all to C functions that # try hard not to call things like malloc(). (Of course, # CPython 2 pretty much did what we're doing.) try: # Close parent's pipe ends if p2cwrite != -1: os.close(p2cwrite) if c2pread != -1: os.close(c2pread) if errread != -1: os.close(errread) os.close(errpipe_read) # When duping fds, if there arises a situation # where one of the fds is either 0, 1 or 2, it # is possible that it is overwritten (#12607). if c2pwrite == 0: c2pwrite = os.dup(c2pwrite) _set_inheritable(c2pwrite, False) while errwrite in (0, 1): errwrite = os.dup(errwrite) _set_inheritable(errwrite, False) # Dup fds for child def _dup2(existing, desired): # dup2() removes the CLOEXEC flag but # we must do it ourselves if dup2() # would be a no-op (issue #10806). if existing == desired: self._set_cloexec_flag(existing, False) elif existing != -1: os.dup2(existing, desired) try: self._remove_nonblock_flag(desired) except OSError: # Ignore EBADF, it may not actually be # open yet. # Tested beginning in 3.7.0b3 test_subprocess.py pass _dup2(p2cread, 0) _dup2(c2pwrite, 1) _dup2(errwrite, 2) # Close pipe fds. Make sure we don't close the # same fd more than once, or standard fds. if not True: closed = set([None]) for fd in (p2cread, c2pwrite, errwrite): if fd not in closed and fd > 2: os.close(fd) closed.add(fd) # Python 3 (with a working set_inheritable): # We no longer manually close p2cread, # c2pwrite, and errwrite here as # _close_open_fds takes care when it is # not already non-inheritable. if cwd is not None: try: os.chdir(cwd) except OSError as e: e._failed_chdir = True raise # Python 3.9 if umask >= 0: os.umask(umask) # XXX: CPython does _Py_RestoreSignals here. # Then setsid() based on ??? try: if gids: os.setgroups(gids) if gid: os.setregid(gid, gid) if uid: os.setreuid(uid, uid) if process_group is not None: os.setpgid(0, process_group) except OSError as e: e._failed_chuser = True raise if preexec_fn: preexec_fn() # Close all other fds, if asked for. This must be done # after preexec_fn runs. if close_fds: fds_to_keep = set(pass_fds) fds_to_keep.add(errpipe_write) self._close_fds(fds_to_keep, errpipe_write) if restore_signals: # restore the documented signals back to sig_dfl; # not all will be defined on every platform for sig in 'SIGPIPE', 'SIGXFZ', 'SIGXFSZ': sig = getattr(signal, sig, None) if sig is not None: signal.signal(sig, signal.SIG_DFL) if start_new_session: os.setsid() try: if env is None: os.execvp(executable, args) else: # Python 3.6 started testing for # bytes values in the env; it also # started encoding strs using # fsencode and using a lower-level # API that takes a list of keys # and values. We don't have access # to that API, so we go the reverse direction. env = {os.fsdecode(k) if isinstance(k, bytes) else k: os.fsdecode(v) if isinstance(v, bytes) else v for k, v in env.items()} os.execvpe(executable, args, env) except OSError as e: e._failed_exec = True raise except: exc_type, exc_value, tb = sys.exc_info() # Save the traceback and attach it to the exception object exc_lines = traceback.format_exception(exc_type, exc_value, tb) exc_value.child_traceback = ''.join(exc_lines) os.write(errpipe_write, pickle.dumps(exc_value)) finally: # Make sure that the process exits no matter what. # The return code does not matter much as it won't be # reported to the application os._exit(1) # Parent self._child_created = True if gc_was_enabled: gc.enable() finally: # be sure the FD is closed no matter what os.close(errpipe_write) # self._devnull is not always defined. devnull_fd = getattr(self, '_devnull', None) if p2cread != -1 and p2cwrite != -1 and p2cread != devnull_fd: os.close(p2cread) if c2pwrite != -1 and c2pread != -1 and c2pwrite != devnull_fd: os.close(c2pwrite) if errwrite != -1 and errread != -1 and errwrite != devnull_fd: os.close(errwrite) if devnull_fd is not None: os.close(devnull_fd) # Prevent a double close of these fds from __init__ on error. self._closed_child_pipe_fds = True # Wait for exec to fail or succeed; possibly raising exception errpipe_read = FileObject(errpipe_read, 'rb') data = errpipe_read.read() finally: try: if hasattr(errpipe_read, 'close'): errpipe_read.close() else: os.close(errpipe_read) except OSError: # Especially on PyPy, we sometimes see the above # `os.close(errpipe_read)` raise an OSError. # It's not entirely clear why, but it happens in # InterprocessSignalTests.test_main sometimes, which must mean # we have some sort of race condition. pass finally: errpipe_read = -1 if data != b"": self.wait() child_exception = pickle.loads(data) for fd in (p2cwrite, c2pread, errread): if fd is not None and fd != -1: os.close(fd) if isinstance(child_exception, OSError): child_exception.filename = executable if hasattr(child_exception, '_failed_chdir'): child_exception.filename = cwd if getattr(child_exception, '_failed_chuser', False): child_exception.filename = None > raise child_exception E OSError: [Errno 8] Exec format error: 'locust' /usr/lib/python3/dist-packages/gevent/subprocess.py:1838: OSError _ StandaloneIntegrationTests.test_webserver_multiple_locustfiles_in_directory __ self = @unittest.skipIf(os.name == "nt", reason="Signal handling on windows is hard") def test_webserver_multiple_locustfiles_in_directory(self): with TemporaryDirectory() as temp_dir: with mock_locustfile(content=MOCK_LOCUSTFILE_CONTENT_A, dir=temp_dir): with mock_locustfile(content=MOCK_LOCUSTFILE_CONTENT_B, dir=temp_dir): > proc = subprocess.Popen(["locust", "-f", temp_dir], stdout=PIPE, stderr=PIPE, text=True) locust/test/test_main.py:314: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3/dist-packages/gevent/subprocess.py:808: in __init__ self._execute_child(args, executable, preexec_fn, close_fds, _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = args = ['locust', '-f', '/tmp/tmpz7seo77c'], executable = 'locust' preexec_fn = None, close_fds = True, pass_fds = (), cwd = None, env = None universal_newlines = None, startupinfo = None, creationflags = 0, shell = False p2cread = -1, p2cwrite = -1, c2pread = 11, c2pwrite = 81, errread = 82 errwrite = 83, restore_signals = True, gid = None, gids = None, uid = None umask = -1, start_new_session = False, process_group = None def _execute_child(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, universal_newlines, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, restore_signals, gid, gids, uid, umask, start_new_session, process_group): """Execute program (POSIX version)""" if isinstance(args, (str, bytes)): args = [args] elif isinstance(args, PathLike): if shell: raise TypeError('path-like args is not allowed when ' 'shell is true') args = [fsencode(args)] # os.PathLike -> [str] else: args = list(args) if shell: # On Android the default shell is at '/system/bin/sh'. unix_shell = ( '/system/bin/sh' if hasattr(sys, 'getandroidapilevel') else '/bin/sh' ) args = [unix_shell, "-c"] + args if executable: args[0] = executable if executable is None: executable = args[0] self._loop.install_sigchld() # For transferring possible exec failure from child to parent # The first char specifies the exception type: 0 means # OSError, 1 means some other error. errpipe_read, errpipe_write = self.pipe_cloexec() # errpipe_write must not be in the standard io 0, 1, or 2 fd range. low_fds_to_close = [] while errpipe_write < 3: low_fds_to_close.append(errpipe_write) errpipe_write = os.dup(errpipe_write) for low_fd in low_fds_to_close: os.close(low_fd) try: try: gc_was_enabled = gc.isenabled() # Disable gc to avoid bug where gc -> file_dealloc -> # write to stderr -> hang. http://bugs.python.org/issue1336 gc.disable() try: self.pid = fork_and_watch(self._on_child, self._loop, True, fork) except: if gc_was_enabled: gc.enable() raise if self.pid == 0: # Child # In various places on the child side of things, we catch OSError # and add attributes to it that detail where in the process we failed; # like all exceptions until we have exec'd, this exception is pickled # and sent to the parent to raise in the calling process. # The parent uses this to decide how to treat that exception, # adjusting certain information about it as needed. # # Python 3.11.8 --- yes, a minor patch release --- stopped # letting the 'filename' parameter get set in the resulting # exception for many cases. We're not quite interpreting this # the same way the stdlib is, I'm sure, but this makes the stdlib # tests pass. # XXX: Technically we're doing a lot of stuff here that # may not be safe to do before a exec(), depending on the OS. # CPython 3 goes to great lengths to precompute a lot # of this info before the fork and pass it all to C functions that # try hard not to call things like malloc(). (Of course, # CPython 2 pretty much did what we're doing.) try: # Close parent's pipe ends if p2cwrite != -1: os.close(p2cwrite) if c2pread != -1: os.close(c2pread) if errread != -1: os.close(errread) os.close(errpipe_read) # When duping fds, if there arises a situation # where one of the fds is either 0, 1 or 2, it # is possible that it is overwritten (#12607). if c2pwrite == 0: c2pwrite = os.dup(c2pwrite) _set_inheritable(c2pwrite, False) while errwrite in (0, 1): errwrite = os.dup(errwrite) _set_inheritable(errwrite, False) # Dup fds for child def _dup2(existing, desired): # dup2() removes the CLOEXEC flag but # we must do it ourselves if dup2() # would be a no-op (issue #10806). if existing == desired: self._set_cloexec_flag(existing, False) elif existing != -1: os.dup2(existing, desired) try: self._remove_nonblock_flag(desired) except OSError: # Ignore EBADF, it may not actually be # open yet. # Tested beginning in 3.7.0b3 test_subprocess.py pass _dup2(p2cread, 0) _dup2(c2pwrite, 1) _dup2(errwrite, 2) # Close pipe fds. Make sure we don't close the # same fd more than once, or standard fds. if not True: closed = set([None]) for fd in (p2cread, c2pwrite, errwrite): if fd not in closed and fd > 2: os.close(fd) closed.add(fd) # Python 3 (with a working set_inheritable): # We no longer manually close p2cread, # c2pwrite, and errwrite here as # _close_open_fds takes care when it is # not already non-inheritable. if cwd is not None: try: os.chdir(cwd) except OSError as e: e._failed_chdir = True raise # Python 3.9 if umask >= 0: os.umask(umask) # XXX: CPython does _Py_RestoreSignals here. # Then setsid() based on ??? try: if gids: os.setgroups(gids) if gid: os.setregid(gid, gid) if uid: os.setreuid(uid, uid) if process_group is not None: os.setpgid(0, process_group) except OSError as e: e._failed_chuser = True raise if preexec_fn: preexec_fn() # Close all other fds, if asked for. This must be done # after preexec_fn runs. if close_fds: fds_to_keep = set(pass_fds) fds_to_keep.add(errpipe_write) self._close_fds(fds_to_keep, errpipe_write) if restore_signals: # restore the documented signals back to sig_dfl; # not all will be defined on every platform for sig in 'SIGPIPE', 'SIGXFZ', 'SIGXFSZ': sig = getattr(signal, sig, None) if sig is not None: signal.signal(sig, signal.SIG_DFL) if start_new_session: os.setsid() try: if env is None: os.execvp(executable, args) else: # Python 3.6 started testing for # bytes values in the env; it also # started encoding strs using # fsencode and using a lower-level # API that takes a list of keys # and values. We don't have access # to that API, so we go the reverse direction. env = {os.fsdecode(k) if isinstance(k, bytes) else k: os.fsdecode(v) if isinstance(v, bytes) else v for k, v in env.items()} os.execvpe(executable, args, env) except OSError as e: e._failed_exec = True raise except: exc_type, exc_value, tb = sys.exc_info() # Save the traceback and attach it to the exception object exc_lines = traceback.format_exception(exc_type, exc_value, tb) exc_value.child_traceback = ''.join(exc_lines) os.write(errpipe_write, pickle.dumps(exc_value)) finally: # Make sure that the process exits no matter what. # The return code does not matter much as it won't be # reported to the application os._exit(1) # Parent self._child_created = True if gc_was_enabled: gc.enable() finally: # be sure the FD is closed no matter what os.close(errpipe_write) # self._devnull is not always defined. devnull_fd = getattr(self, '_devnull', None) if p2cread != -1 and p2cwrite != -1 and p2cread != devnull_fd: os.close(p2cread) if c2pwrite != -1 and c2pread != -1 and c2pwrite != devnull_fd: os.close(c2pwrite) if errwrite != -1 and errread != -1 and errwrite != devnull_fd: os.close(errwrite) if devnull_fd is not None: os.close(devnull_fd) # Prevent a double close of these fds from __init__ on error. self._closed_child_pipe_fds = True # Wait for exec to fail or succeed; possibly raising exception errpipe_read = FileObject(errpipe_read, 'rb') data = errpipe_read.read() finally: try: if hasattr(errpipe_read, 'close'): errpipe_read.close() else: os.close(errpipe_read) except OSError: # Especially on PyPy, we sometimes see the above # `os.close(errpipe_read)` raise an OSError. # It's not entirely clear why, but it happens in # InterprocessSignalTests.test_main sometimes, which must mean # we have some sort of race condition. pass finally: errpipe_read = -1 if data != b"": self.wait() child_exception = pickle.loads(data) for fd in (p2cwrite, c2pread, errread): if fd is not None and fd != -1: os.close(fd) if isinstance(child_exception, OSError): child_exception.filename = executable if hasattr(child_exception, '_failed_chdir'): child_exception.filename = cwd if getattr(child_exception, '_failed_chuser', False): child_exception.filename = None > raise child_exception E OSError: [Errno 8] Exec format error: 'locust' /usr/lib/python3/dist-packages/gevent/subprocess.py:1838: OSError __ StandaloneIntegrationTests.test_webserver_multiple_locustfiles_with_shape ___ self = @unittest.skipIf(os.name == "nt", reason="Signal handling on windows is hard") def test_webserver_multiple_locustfiles_with_shape(self): content = textwrap.dedent( """ from locust import User, task, between class TestUser2(User): wait_time = between(2, 4) @task def my_task(self): print("running my_task() again") """ ) with mock_locustfile(content=content) as mocked1: with temporary_file( content=textwrap.dedent( """ from locust import User, task, between, LoadTestShape class LoadTestShape(LoadTestShape): def tick(self): run_time = self.get_run_time() if run_time < 2: return (10, 1) return None class TestUser(User): wait_time = between(2, 4) @task def my_task(self): print("running my_task()") """ ) ) as mocked2: > proc = subprocess.Popen( ["locust", "-f", f"{mocked1.file_path},{mocked2}"], stdout=PIPE, stderr=PIPE, text=True ) locust/test/test_main.py:357: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3/dist-packages/gevent/subprocess.py:808: in __init__ self._execute_child(args, executable, preexec_fn, close_fds, _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = args = ['locust', '-f', '/build/reproducible-path/locust-2.24.0/locust/test/mock_locustfile_1715256386_4839547_72764.py,/tmp/tmpgjoue2k7_locustfile.py'] executable = 'locust', preexec_fn = None, close_fds = True, pass_fds = () cwd = None, env = None, universal_newlines = None, startupinfo = None creationflags = 0, shell = False, p2cread = -1, p2cwrite = -1, c2pread = 11 c2pwrite = 81, errread = 82, errwrite = 83, restore_signals = True, gid = None gids = None, uid = None, umask = -1, start_new_session = False process_group = None def _execute_child(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, universal_newlines, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, restore_signals, gid, gids, uid, umask, start_new_session, process_group): """Execute program (POSIX version)""" if isinstance(args, (str, bytes)): args = [args] elif isinstance(args, PathLike): if shell: raise TypeError('path-like args is not allowed when ' 'shell is true') args = [fsencode(args)] # os.PathLike -> [str] else: args = list(args) if shell: # On Android the default shell is at '/system/bin/sh'. unix_shell = ( '/system/bin/sh' if hasattr(sys, 'getandroidapilevel') else '/bin/sh' ) args = [unix_shell, "-c"] + args if executable: args[0] = executable if executable is None: executable = args[0] self._loop.install_sigchld() # For transferring possible exec failure from child to parent # The first char specifies the exception type: 0 means # OSError, 1 means some other error. errpipe_read, errpipe_write = self.pipe_cloexec() # errpipe_write must not be in the standard io 0, 1, or 2 fd range. low_fds_to_close = [] while errpipe_write < 3: low_fds_to_close.append(errpipe_write) errpipe_write = os.dup(errpipe_write) for low_fd in low_fds_to_close: os.close(low_fd) try: try: gc_was_enabled = gc.isenabled() # Disable gc to avoid bug where gc -> file_dealloc -> # write to stderr -> hang. http://bugs.python.org/issue1336 gc.disable() try: self.pid = fork_and_watch(self._on_child, self._loop, True, fork) except: if gc_was_enabled: gc.enable() raise if self.pid == 0: # Child # In various places on the child side of things, we catch OSError # and add attributes to it that detail where in the process we failed; # like all exceptions until we have exec'd, this exception is pickled # and sent to the parent to raise in the calling process. # The parent uses this to decide how to treat that exception, # adjusting certain information about it as needed. # # Python 3.11.8 --- yes, a minor patch release --- stopped # letting the 'filename' parameter get set in the resulting # exception for many cases. We're not quite interpreting this # the same way the stdlib is, I'm sure, but this makes the stdlib # tests pass. # XXX: Technically we're doing a lot of stuff here that # may not be safe to do before a exec(), depending on the OS. # CPython 3 goes to great lengths to precompute a lot # of this info before the fork and pass it all to C functions that # try hard not to call things like malloc(). (Of course, # CPython 2 pretty much did what we're doing.) try: # Close parent's pipe ends if p2cwrite != -1: os.close(p2cwrite) if c2pread != -1: os.close(c2pread) if errread != -1: os.close(errread) os.close(errpipe_read) # When duping fds, if there arises a situation # where one of the fds is either 0, 1 or 2, it # is possible that it is overwritten (#12607). if c2pwrite == 0: c2pwrite = os.dup(c2pwrite) _set_inheritable(c2pwrite, False) while errwrite in (0, 1): errwrite = os.dup(errwrite) _set_inheritable(errwrite, False) # Dup fds for child def _dup2(existing, desired): # dup2() removes the CLOEXEC flag but # we must do it ourselves if dup2() # would be a no-op (issue #10806). if existing == desired: self._set_cloexec_flag(existing, False) elif existing != -1: os.dup2(existing, desired) try: self._remove_nonblock_flag(desired) except OSError: # Ignore EBADF, it may not actually be # open yet. # Tested beginning in 3.7.0b3 test_subprocess.py pass _dup2(p2cread, 0) _dup2(c2pwrite, 1) _dup2(errwrite, 2) # Close pipe fds. Make sure we don't close the # same fd more than once, or standard fds. if not True: closed = set([None]) for fd in (p2cread, c2pwrite, errwrite): if fd not in closed and fd > 2: os.close(fd) closed.add(fd) # Python 3 (with a working set_inheritable): # We no longer manually close p2cread, # c2pwrite, and errwrite here as # _close_open_fds takes care when it is # not already non-inheritable. if cwd is not None: try: os.chdir(cwd) except OSError as e: e._failed_chdir = True raise # Python 3.9 if umask >= 0: os.umask(umask) # XXX: CPython does _Py_RestoreSignals here. # Then setsid() based on ??? try: if gids: os.setgroups(gids) if gid: os.setregid(gid, gid) if uid: os.setreuid(uid, uid) if process_group is not None: os.setpgid(0, process_group) except OSError as e: e._failed_chuser = True raise if preexec_fn: preexec_fn() # Close all other fds, if asked for. This must be done # after preexec_fn runs. if close_fds: fds_to_keep = set(pass_fds) fds_to_keep.add(errpipe_write) self._close_fds(fds_to_keep, errpipe_write) if restore_signals: # restore the documented signals back to sig_dfl; # not all will be defined on every platform for sig in 'SIGPIPE', 'SIGXFZ', 'SIGXFSZ': sig = getattr(signal, sig, None) if sig is not None: signal.signal(sig, signal.SIG_DFL) if start_new_session: os.setsid() try: if env is None: os.execvp(executable, args) else: # Python 3.6 started testing for # bytes values in the env; it also # started encoding strs using # fsencode and using a lower-level # API that takes a list of keys # and values. We don't have access # to that API, so we go the reverse direction. env = {os.fsdecode(k) if isinstance(k, bytes) else k: os.fsdecode(v) if isinstance(v, bytes) else v for k, v in env.items()} os.execvpe(executable, args, env) except OSError as e: e._failed_exec = True raise except: exc_type, exc_value, tb = sys.exc_info() # Save the traceback and attach it to the exception object exc_lines = traceback.format_exception(exc_type, exc_value, tb) exc_value.child_traceback = ''.join(exc_lines) os.write(errpipe_write, pickle.dumps(exc_value)) finally: # Make sure that the process exits no matter what. # The return code does not matter much as it won't be # reported to the application os._exit(1) # Parent self._child_created = True if gc_was_enabled: gc.enable() finally: # be sure the FD is closed no matter what os.close(errpipe_write) # self._devnull is not always defined. devnull_fd = getattr(self, '_devnull', None) if p2cread != -1 and p2cwrite != -1 and p2cread != devnull_fd: os.close(p2cread) if c2pwrite != -1 and c2pread != -1 and c2pwrite != devnull_fd: os.close(c2pwrite) if errwrite != -1 and errread != -1 and errwrite != devnull_fd: os.close(errwrite) if devnull_fd is not None: os.close(devnull_fd) # Prevent a double close of these fds from __init__ on error. self._closed_child_pipe_fds = True # Wait for exec to fail or succeed; possibly raising exception errpipe_read = FileObject(errpipe_read, 'rb') data = errpipe_read.read() finally: try: if hasattr(errpipe_read, 'close'): errpipe_read.close() else: os.close(errpipe_read) except OSError: # Especially on PyPy, we sometimes see the above # `os.close(errpipe_read)` raise an OSError. # It's not entirely clear why, but it happens in # InterprocessSignalTests.test_main sometimes, which must mean # we have some sort of race condition. pass finally: errpipe_read = -1 if data != b"": self.wait() child_exception = pickle.loads(data) for fd in (p2cwrite, c2pread, errread): if fd is not None and fd != -1: os.close(fd) if isinstance(child_exception, OSError): child_exception.filename = executable if hasattr(child_exception, '_failed_chdir'): child_exception.filename = cwd if getattr(child_exception, '_failed_chuser', False): child_exception.filename = None > raise child_exception E OSError: [Errno 8] Exec format error: 'locust' /usr/lib/python3/dist-packages/gevent/subprocess.py:1838: OSError _________________ DistributedIntegrationTests.test_distributed _________________ self = def test_distributed(self): LOCUSTFILE_CONTENT = textwrap.dedent( """ from locust import User, task, constant class User1(User): wait_time = constant(1) @task def t(self): pass """ ) with mock_locustfile(content=LOCUSTFILE_CONTENT) as mocked: > proc = subprocess.Popen( [ "locust", "-f", mocked.file_path, "--headless", "--master", "--expect-workers", "1", "-u", "3", "-t", "5s", ], stderr=STDOUT, stdout=PIPE, text=True, ) locust/test/test_main.py:1570: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3/dist-packages/gevent/subprocess.py:808: in __init__ self._execute_child(args, executable, preexec_fn, close_fds, _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = args = ['locust', '-f', '/build/reproducible-path/locust-2.24.0/locust/test/mock_locustfile_1715256386_698283_48825.py', '--headless', '--master', '--expect-workers', ...] executable = 'locust', preexec_fn = None, close_fds = True, pass_fds = () cwd = None, env = None, universal_newlines = None, startupinfo = None creationflags = 0, shell = False, p2cread = -1, p2cwrite = -1, c2pread = 11 c2pwrite = 81, errread = -1, errwrite = 81, restore_signals = True, gid = None gids = None, uid = None, umask = -1, start_new_session = False process_group = None def _execute_child(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, universal_newlines, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, restore_signals, gid, gids, uid, umask, start_new_session, process_group): """Execute program (POSIX version)""" if isinstance(args, (str, bytes)): args = [args] elif isinstance(args, PathLike): if shell: raise TypeError('path-like args is not allowed when ' 'shell is true') args = [fsencode(args)] # os.PathLike -> [str] else: args = list(args) if shell: # On Android the default shell is at '/system/bin/sh'. unix_shell = ( '/system/bin/sh' if hasattr(sys, 'getandroidapilevel') else '/bin/sh' ) args = [unix_shell, "-c"] + args if executable: args[0] = executable if executable is None: executable = args[0] self._loop.install_sigchld() # For transferring possible exec failure from child to parent # The first char specifies the exception type: 0 means # OSError, 1 means some other error. errpipe_read, errpipe_write = self.pipe_cloexec() # errpipe_write must not be in the standard io 0, 1, or 2 fd range. low_fds_to_close = [] while errpipe_write < 3: low_fds_to_close.append(errpipe_write) errpipe_write = os.dup(errpipe_write) for low_fd in low_fds_to_close: os.close(low_fd) try: try: gc_was_enabled = gc.isenabled() # Disable gc to avoid bug where gc -> file_dealloc -> # write to stderr -> hang. http://bugs.python.org/issue1336 gc.disable() try: self.pid = fork_and_watch(self._on_child, self._loop, True, fork) except: if gc_was_enabled: gc.enable() raise if self.pid == 0: # Child # In various places on the child side of things, we catch OSError # and add attributes to it that detail where in the process we failed; # like all exceptions until we have exec'd, this exception is pickled # and sent to the parent to raise in the calling process. # The parent uses this to decide how to treat that exception, # adjusting certain information about it as needed. # # Python 3.11.8 --- yes, a minor patch release --- stopped # letting the 'filename' parameter get set in the resulting # exception for many cases. We're not quite interpreting this # the same way the stdlib is, I'm sure, but this makes the stdlib # tests pass. # XXX: Technically we're doing a lot of stuff here that # may not be safe to do before a exec(), depending on the OS. # CPython 3 goes to great lengths to precompute a lot # of this info before the fork and pass it all to C functions that # try hard not to call things like malloc(). (Of course, # CPython 2 pretty much did what we're doing.) try: # Close parent's pipe ends if p2cwrite != -1: os.close(p2cwrite) if c2pread != -1: os.close(c2pread) if errread != -1: os.close(errread) os.close(errpipe_read) # When duping fds, if there arises a situation # where one of the fds is either 0, 1 or 2, it # is possible that it is overwritten (#12607). if c2pwrite == 0: c2pwrite = os.dup(c2pwrite) _set_inheritable(c2pwrite, False) while errwrite in (0, 1): errwrite = os.dup(errwrite) _set_inheritable(errwrite, False) # Dup fds for child def _dup2(existing, desired): # dup2() removes the CLOEXEC flag but # we must do it ourselves if dup2() # would be a no-op (issue #10806). if existing == desired: self._set_cloexec_flag(existing, False) elif existing != -1: os.dup2(existing, desired) try: self._remove_nonblock_flag(desired) except OSError: # Ignore EBADF, it may not actually be # open yet. # Tested beginning in 3.7.0b3 test_subprocess.py pass _dup2(p2cread, 0) _dup2(c2pwrite, 1) _dup2(errwrite, 2) # Close pipe fds. Make sure we don't close the # same fd more than once, or standard fds. if not True: closed = set([None]) for fd in (p2cread, c2pwrite, errwrite): if fd not in closed and fd > 2: os.close(fd) closed.add(fd) # Python 3 (with a working set_inheritable): # We no longer manually close p2cread, # c2pwrite, and errwrite here as # _close_open_fds takes care when it is # not already non-inheritable. if cwd is not None: try: os.chdir(cwd) except OSError as e: e._failed_chdir = True raise # Python 3.9 if umask >= 0: os.umask(umask) # XXX: CPython does _Py_RestoreSignals here. # Then setsid() based on ??? try: if gids: os.setgroups(gids) if gid: os.setregid(gid, gid) if uid: os.setreuid(uid, uid) if process_group is not None: os.setpgid(0, process_group) except OSError as e: e._failed_chuser = True raise if preexec_fn: preexec_fn() # Close all other fds, if asked for. This must be done # after preexec_fn runs. if close_fds: fds_to_keep = set(pass_fds) fds_to_keep.add(errpipe_write) self._close_fds(fds_to_keep, errpipe_write) if restore_signals: # restore the documented signals back to sig_dfl; # not all will be defined on every platform for sig in 'SIGPIPE', 'SIGXFZ', 'SIGXFSZ': sig = getattr(signal, sig, None) if sig is not None: signal.signal(sig, signal.SIG_DFL) if start_new_session: os.setsid() try: if env is None: os.execvp(executable, args) else: # Python 3.6 started testing for # bytes values in the env; it also # started encoding strs using # fsencode and using a lower-level # API that takes a list of keys # and values. We don't have access # to that API, so we go the reverse direction. env = {os.fsdecode(k) if isinstance(k, bytes) else k: os.fsdecode(v) if isinstance(v, bytes) else v for k, v in env.items()} os.execvpe(executable, args, env) except OSError as e: e._failed_exec = True raise except: exc_type, exc_value, tb = sys.exc_info() # Save the traceback and attach it to the exception object exc_lines = traceback.format_exception(exc_type, exc_value, tb) exc_value.child_traceback = ''.join(exc_lines) os.write(errpipe_write, pickle.dumps(exc_value)) finally: # Make sure that the process exits no matter what. # The return code does not matter much as it won't be # reported to the application os._exit(1) # Parent self._child_created = True if gc_was_enabled: gc.enable() finally: # be sure the FD is closed no matter what os.close(errpipe_write) # self._devnull is not always defined. devnull_fd = getattr(self, '_devnull', None) if p2cread != -1 and p2cwrite != -1 and p2cread != devnull_fd: os.close(p2cread) if c2pwrite != -1 and c2pread != -1 and c2pwrite != devnull_fd: os.close(c2pwrite) if errwrite != -1 and errread != -1 and errwrite != devnull_fd: os.close(errwrite) if devnull_fd is not None: os.close(devnull_fd) # Prevent a double close of these fds from __init__ on error. self._closed_child_pipe_fds = True # Wait for exec to fail or succeed; possibly raising exception errpipe_read = FileObject(errpipe_read, 'rb') data = errpipe_read.read() finally: try: if hasattr(errpipe_read, 'close'): errpipe_read.close() else: os.close(errpipe_read) except OSError: # Especially on PyPy, we sometimes see the above # `os.close(errpipe_read)` raise an OSError. # It's not entirely clear why, but it happens in # InterprocessSignalTests.test_main sometimes, which must mean # we have some sort of race condition. pass finally: errpipe_read = -1 if data != b"": self.wait() child_exception = pickle.loads(data) for fd in (p2cwrite, c2pread, errread): if fd is not None and fd != -1: os.close(fd) if isinstance(child_exception, OSError): child_exception.filename = executable if hasattr(child_exception, '_failed_chdir'): child_exception.filename = cwd if getattr(child_exception, '_failed_chuser', False): child_exception.filename = None > raise child_exception E OSError: [Errno 8] Exec format error: 'locust' /usr/lib/python3/dist-packages/gevent/subprocess.py:1838: OSError _____________ DistributedIntegrationTests.test_distributed_events ______________ self = def test_distributed_events(self): content = ( MOCK_LOCUSTFILE_CONTENT + """ from locust import events from locust.runners import MasterRunner @events.test_start.add_listener def on_test_start(environment, **kwargs): if isinstance(environment.runner, MasterRunner): print("test_start on master") else: print("test_start on worker") @events.test_stop.add_listener def on_test_stop(environment, **kwargs): if isinstance(environment.runner, MasterRunner): print("test_stop on master") else: print("test_stop on worker") """ ) with mock_locustfile(content=content) as mocked: > proc = subprocess.Popen( [ "locust", "-f", mocked.file_path, "--headless", "--master", "--expect-workers", "1", "-t", "1", "--exit-code-on-error", "0", "-L", "DEBUG", ], stdout=PIPE, stderr=PIPE, text=True, ) locust/test/test_main.py:1448: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3/dist-packages/gevent/subprocess.py:808: in __init__ self._execute_child(args, executable, preexec_fn, close_fds, _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = args = ['locust', '-f', '/build/reproducible-path/locust-2.24.0/locust/test/mock_locustfile_1715256386_9062076_54681.py', '--headless', '--master', '--expect-workers', ...] executable = 'locust', preexec_fn = None, close_fds = True, pass_fds = () cwd = None, env = None, universal_newlines = None, startupinfo = None creationflags = 0, shell = False, p2cread = -1, p2cwrite = -1, c2pread = 11 c2pwrite = 81, errread = 82, errwrite = 83, restore_signals = True, gid = None gids = None, uid = None, umask = -1, start_new_session = False process_group = None def _execute_child(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, universal_newlines, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, restore_signals, gid, gids, uid, umask, start_new_session, process_group): """Execute program (POSIX version)""" if isinstance(args, (str, bytes)): args = [args] elif isinstance(args, PathLike): if shell: raise TypeError('path-like args is not allowed when ' 'shell is true') args = [fsencode(args)] # os.PathLike -> [str] else: args = list(args) if shell: # On Android the default shell is at '/system/bin/sh'. unix_shell = ( '/system/bin/sh' if hasattr(sys, 'getandroidapilevel') else '/bin/sh' ) args = [unix_shell, "-c"] + args if executable: args[0] = executable if executable is None: executable = args[0] self._loop.install_sigchld() # For transferring possible exec failure from child to parent # The first char specifies the exception type: 0 means # OSError, 1 means some other error. errpipe_read, errpipe_write = self.pipe_cloexec() # errpipe_write must not be in the standard io 0, 1, or 2 fd range. low_fds_to_close = [] while errpipe_write < 3: low_fds_to_close.append(errpipe_write) errpipe_write = os.dup(errpipe_write) for low_fd in low_fds_to_close: os.close(low_fd) try: try: gc_was_enabled = gc.isenabled() # Disable gc to avoid bug where gc -> file_dealloc -> # write to stderr -> hang. http://bugs.python.org/issue1336 gc.disable() try: self.pid = fork_and_watch(self._on_child, self._loop, True, fork) except: if gc_was_enabled: gc.enable() raise if self.pid == 0: # Child # In various places on the child side of things, we catch OSError # and add attributes to it that detail where in the process we failed; # like all exceptions until we have exec'd, this exception is pickled # and sent to the parent to raise in the calling process. # The parent uses this to decide how to treat that exception, # adjusting certain information about it as needed. # # Python 3.11.8 --- yes, a minor patch release --- stopped # letting the 'filename' parameter get set in the resulting # exception for many cases. We're not quite interpreting this # the same way the stdlib is, I'm sure, but this makes the stdlib # tests pass. # XXX: Technically we're doing a lot of stuff here that # may not be safe to do before a exec(), depending on the OS. # CPython 3 goes to great lengths to precompute a lot # of this info before the fork and pass it all to C functions that # try hard not to call things like malloc(). (Of course, # CPython 2 pretty much did what we're doing.) try: # Close parent's pipe ends if p2cwrite != -1: os.close(p2cwrite) if c2pread != -1: os.close(c2pread) if errread != -1: os.close(errread) os.close(errpipe_read) # When duping fds, if there arises a situation # where one of the fds is either 0, 1 or 2, it # is possible that it is overwritten (#12607). if c2pwrite == 0: c2pwrite = os.dup(c2pwrite) _set_inheritable(c2pwrite, False) while errwrite in (0, 1): errwrite = os.dup(errwrite) _set_inheritable(errwrite, False) # Dup fds for child def _dup2(existing, desired): # dup2() removes the CLOEXEC flag but # we must do it ourselves if dup2() # would be a no-op (issue #10806). if existing == desired: self._set_cloexec_flag(existing, False) elif existing != -1: os.dup2(existing, desired) try: self._remove_nonblock_flag(desired) except OSError: # Ignore EBADF, it may not actually be # open yet. # Tested beginning in 3.7.0b3 test_subprocess.py pass _dup2(p2cread, 0) _dup2(c2pwrite, 1) _dup2(errwrite, 2) # Close pipe fds. Make sure we don't close the # same fd more than once, or standard fds. if not True: closed = set([None]) for fd in (p2cread, c2pwrite, errwrite): if fd not in closed and fd > 2: os.close(fd) closed.add(fd) # Python 3 (with a working set_inheritable): # We no longer manually close p2cread, # c2pwrite, and errwrite here as # _close_open_fds takes care when it is # not already non-inheritable. if cwd is not None: try: os.chdir(cwd) except OSError as e: e._failed_chdir = True raise # Python 3.9 if umask >= 0: os.umask(umask) # XXX: CPython does _Py_RestoreSignals here. # Then setsid() based on ??? try: if gids: os.setgroups(gids) if gid: os.setregid(gid, gid) if uid: os.setreuid(uid, uid) if process_group is not None: os.setpgid(0, process_group) except OSError as e: e._failed_chuser = True raise if preexec_fn: preexec_fn() # Close all other fds, if asked for. This must be done # after preexec_fn runs. if close_fds: fds_to_keep = set(pass_fds) fds_to_keep.add(errpipe_write) self._close_fds(fds_to_keep, errpipe_write) if restore_signals: # restore the documented signals back to sig_dfl; # not all will be defined on every platform for sig in 'SIGPIPE', 'SIGXFZ', 'SIGXFSZ': sig = getattr(signal, sig, None) if sig is not None: signal.signal(sig, signal.SIG_DFL) if start_new_session: os.setsid() try: if env is None: os.execvp(executable, args) else: # Python 3.6 started testing for # bytes values in the env; it also # started encoding strs using # fsencode and using a lower-level # API that takes a list of keys # and values. We don't have access # to that API, so we go the reverse direction. env = {os.fsdecode(k) if isinstance(k, bytes) else k: os.fsdecode(v) if isinstance(v, bytes) else v for k, v in env.items()} os.execvpe(executable, args, env) except OSError as e: e._failed_exec = True raise except: exc_type, exc_value, tb = sys.exc_info() # Save the traceback and attach it to the exception object exc_lines = traceback.format_exception(exc_type, exc_value, tb) exc_value.child_traceback = ''.join(exc_lines) os.write(errpipe_write, pickle.dumps(exc_value)) finally: # Make sure that the process exits no matter what. # The return code does not matter much as it won't be # reported to the application os._exit(1) # Parent self._child_created = True if gc_was_enabled: gc.enable() finally: # be sure the FD is closed no matter what os.close(errpipe_write) # self._devnull is not always defined. devnull_fd = getattr(self, '_devnull', None) if p2cread != -1 and p2cwrite != -1 and p2cread != devnull_fd: os.close(p2cread) if c2pwrite != -1 and c2pread != -1 and c2pwrite != devnull_fd: os.close(c2pwrite) if errwrite != -1 and errread != -1 and errwrite != devnull_fd: os.close(errwrite) if devnull_fd is not None: os.close(devnull_fd) # Prevent a double close of these fds from __init__ on error. self._closed_child_pipe_fds = True # Wait for exec to fail or succeed; possibly raising exception errpipe_read = FileObject(errpipe_read, 'rb') data = errpipe_read.read() finally: try: if hasattr(errpipe_read, 'close'): errpipe_read.close() else: os.close(errpipe_read) except OSError: # Especially on PyPy, we sometimes see the above # `os.close(errpipe_read)` raise an OSError. # It's not entirely clear why, but it happens in # InterprocessSignalTests.test_main sometimes, which must mean # we have some sort of race condition. pass finally: errpipe_read = -1 if data != b"": self.wait() child_exception = pickle.loads(data) for fd in (p2cwrite, c2pread, errread): if fd is not None and fd != -1: os.close(fd) if isinstance(child_exception, OSError): child_exception.filename = executable if hasattr(child_exception, '_failed_chdir'): child_exception.filename = cwd if getattr(child_exception, '_failed_chuser', False): child_exception.filename = None > raise child_exception E OSError: [Errno 8] Exec format error: 'locust' /usr/lib/python3/dist-packages/gevent/subprocess.py:1838: OSError _____ DistributedIntegrationTests.test_distributed_report_timeout_expired ______ self = def test_distributed_report_timeout_expired(self): LOCUSTFILE_CONTENT = textwrap.dedent( """ from locust import User, task, constant class User1(User): wait_time = constant(1) @task def t(self): pass """ ) with mock_locustfile(content=LOCUSTFILE_CONTENT) as mocked, patch_env( "LOCUST_WAIT_FOR_WORKERS_REPORT_AFTER_RAMP_UP", "0.01" ) as _: > proc = subprocess.Popen( [ "locust", "-f", mocked.file_path, "--headless", "--master", "--expect-workers", "1", "-u", "3", "-t", "5s", ], stderr=STDOUT, stdout=PIPE, text=True, ) locust/test/test_main.py:1624: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3/dist-packages/gevent/subprocess.py:808: in __init__ self._execute_child(args, executable, preexec_fn, close_fds, _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = args = ['locust', '-f', '/build/reproducible-path/locust-2.24.0/locust/test/mock_locustfile_1715256387_2981977_84365.py', '--headless', '--master', '--expect-workers', ...] executable = 'locust', preexec_fn = None, close_fds = True, pass_fds = () cwd = None, env = None, universal_newlines = None, startupinfo = None creationflags = 0, shell = False, p2cread = -1, p2cwrite = -1, c2pread = 11 c2pwrite = 81, errread = -1, errwrite = 81, restore_signals = True, gid = None gids = None, uid = None, umask = -1, start_new_session = False process_group = None def _execute_child(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, universal_newlines, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, restore_signals, gid, gids, uid, umask, start_new_session, process_group): """Execute program (POSIX version)""" if isinstance(args, (str, bytes)): args = [args] elif isinstance(args, PathLike): if shell: raise TypeError('path-like args is not allowed when ' 'shell is true') args = [fsencode(args)] # os.PathLike -> [str] else: args = list(args) if shell: # On Android the default shell is at '/system/bin/sh'. unix_shell = ( '/system/bin/sh' if hasattr(sys, 'getandroidapilevel') else '/bin/sh' ) args = [unix_shell, "-c"] + args if executable: args[0] = executable if executable is None: executable = args[0] self._loop.install_sigchld() # For transferring possible exec failure from child to parent # The first char specifies the exception type: 0 means # OSError, 1 means some other error. errpipe_read, errpipe_write = self.pipe_cloexec() # errpipe_write must not be in the standard io 0, 1, or 2 fd range. low_fds_to_close = [] while errpipe_write < 3: low_fds_to_close.append(errpipe_write) errpipe_write = os.dup(errpipe_write) for low_fd in low_fds_to_close: os.close(low_fd) try: try: gc_was_enabled = gc.isenabled() # Disable gc to avoid bug where gc -> file_dealloc -> # write to stderr -> hang. http://bugs.python.org/issue1336 gc.disable() try: self.pid = fork_and_watch(self._on_child, self._loop, True, fork) except: if gc_was_enabled: gc.enable() raise if self.pid == 0: # Child # In various places on the child side of things, we catch OSError # and add attributes to it that detail where in the process we failed; # like all exceptions until we have exec'd, this exception is pickled # and sent to the parent to raise in the calling process. # The parent uses this to decide how to treat that exception, # adjusting certain information about it as needed. # # Python 3.11.8 --- yes, a minor patch release --- stopped # letting the 'filename' parameter get set in the resulting # exception for many cases. We're not quite interpreting this # the same way the stdlib is, I'm sure, but this makes the stdlib # tests pass. # XXX: Technically we're doing a lot of stuff here that # may not be safe to do before a exec(), depending on the OS. # CPython 3 goes to great lengths to precompute a lot # of this info before the fork and pass it all to C functions that # try hard not to call things like malloc(). (Of course, # CPython 2 pretty much did what we're doing.) try: # Close parent's pipe ends if p2cwrite != -1: os.close(p2cwrite) if c2pread != -1: os.close(c2pread) if errread != -1: os.close(errread) os.close(errpipe_read) # When duping fds, if there arises a situation # where one of the fds is either 0, 1 or 2, it # is possible that it is overwritten (#12607). if c2pwrite == 0: c2pwrite = os.dup(c2pwrite) _set_inheritable(c2pwrite, False) while errwrite in (0, 1): errwrite = os.dup(errwrite) _set_inheritable(errwrite, False) # Dup fds for child def _dup2(existing, desired): # dup2() removes the CLOEXEC flag but # we must do it ourselves if dup2() # would be a no-op (issue #10806). if existing == desired: self._set_cloexec_flag(existing, False) elif existing != -1: os.dup2(existing, desired) try: self._remove_nonblock_flag(desired) except OSError: # Ignore EBADF, it may not actually be # open yet. # Tested beginning in 3.7.0b3 test_subprocess.py pass _dup2(p2cread, 0) _dup2(c2pwrite, 1) _dup2(errwrite, 2) # Close pipe fds. Make sure we don't close the # same fd more than once, or standard fds. if not True: closed = set([None]) for fd in (p2cread, c2pwrite, errwrite): if fd not in closed and fd > 2: os.close(fd) closed.add(fd) # Python 3 (with a working set_inheritable): # We no longer manually close p2cread, # c2pwrite, and errwrite here as # _close_open_fds takes care when it is # not already non-inheritable. if cwd is not None: try: os.chdir(cwd) except OSError as e: e._failed_chdir = True raise # Python 3.9 if umask >= 0: os.umask(umask) # XXX: CPython does _Py_RestoreSignals here. # Then setsid() based on ??? try: if gids: os.setgroups(gids) if gid: os.setregid(gid, gid) if uid: os.setreuid(uid, uid) if process_group is not None: os.setpgid(0, process_group) except OSError as e: e._failed_chuser = True raise if preexec_fn: preexec_fn() # Close all other fds, if asked for. This must be done # after preexec_fn runs. if close_fds: fds_to_keep = set(pass_fds) fds_to_keep.add(errpipe_write) self._close_fds(fds_to_keep, errpipe_write) if restore_signals: # restore the documented signals back to sig_dfl; # not all will be defined on every platform for sig in 'SIGPIPE', 'SIGXFZ', 'SIGXFSZ': sig = getattr(signal, sig, None) if sig is not None: signal.signal(sig, signal.SIG_DFL) if start_new_session: os.setsid() try: if env is None: os.execvp(executable, args) else: # Python 3.6 started testing for # bytes values in the env; it also # started encoding strs using # fsencode and using a lower-level # API that takes a list of keys # and values. We don't have access # to that API, so we go the reverse direction. env = {os.fsdecode(k) if isinstance(k, bytes) else k: os.fsdecode(v) if isinstance(v, bytes) else v for k, v in env.items()} os.execvpe(executable, args, env) except OSError as e: e._failed_exec = True raise except: exc_type, exc_value, tb = sys.exc_info() # Save the traceback and attach it to the exception object exc_lines = traceback.format_exception(exc_type, exc_value, tb) exc_value.child_traceback = ''.join(exc_lines) os.write(errpipe_write, pickle.dumps(exc_value)) finally: # Make sure that the process exits no matter what. # The return code does not matter much as it won't be # reported to the application os._exit(1) # Parent self._child_created = True if gc_was_enabled: gc.enable() finally: # be sure the FD is closed no matter what os.close(errpipe_write) # self._devnull is not always defined. devnull_fd = getattr(self, '_devnull', None) if p2cread != -1 and p2cwrite != -1 and p2cread != devnull_fd: os.close(p2cread) if c2pwrite != -1 and c2pread != -1 and c2pwrite != devnull_fd: os.close(c2pwrite) if errwrite != -1 and errread != -1 and errwrite != devnull_fd: os.close(errwrite) if devnull_fd is not None: os.close(devnull_fd) # Prevent a double close of these fds from __init__ on error. self._closed_child_pipe_fds = True # Wait for exec to fail or succeed; possibly raising exception errpipe_read = FileObject(errpipe_read, 'rb') data = errpipe_read.read() finally: try: if hasattr(errpipe_read, 'close'): errpipe_read.close() else: os.close(errpipe_read) except OSError: # Especially on PyPy, we sometimes see the above # `os.close(errpipe_read)` raise an OSError. # It's not entirely clear why, but it happens in # InterprocessSignalTests.test_main sometimes, which must mean # we have some sort of race condition. pass finally: errpipe_read = -1 if data != b"": self.wait() child_exception = pickle.loads(data) for fd in (p2cwrite, c2pread, errread): if fd is not None and fd != -1: os.close(fd) if isinstance(child_exception, OSError): child_exception.filename = executable if hasattr(child_exception, '_failed_chdir'): child_exception.filename = cwd if getattr(child_exception, '_failed_chuser', False): child_exception.filename = None > raise child_exception E OSError: [Errno 8] Exec format error: 'locust' /usr/lib/python3/dist-packages/gevent/subprocess.py:1838: OSError ______________ DistributedIntegrationTests.test_distributed_tags _______________ self = def test_distributed_tags(self): content = """ from locust import HttpUser, TaskSet, task, between, LoadTestShape, tag class SecondUser(HttpUser): host = "http://127.0.0.1:8089" wait_time = between(0, 0.1) @tag("tag1") @task def task1(self): print("task1") @tag("tag2") @task def task2(self): print("task2") """ with mock_locustfile(content=content) as mocked: > proc = subprocess.Popen( [ "locust", "-f", mocked.file_path, "--headless", "--master", "--expect-workers", "1", "-t", "1", "-u", "2", "--exit-code-on-error", "0", "-L", "DEBUG", "--tags", "tag1", ], stdout=PIPE, stderr=PIPE, text=True, ) locust/test/test_main.py:1509: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3/dist-packages/gevent/subprocess.py:808: in __init__ self._execute_child(args, executable, preexec_fn, close_fds, _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = args = ['locust', '-f', '/build/reproducible-path/locust-2.24.0/locust/test/mock_locustfile_1715256387_4957745_95543.py', '--headless', '--master', '--expect-workers', ...] executable = 'locust', preexec_fn = None, close_fds = True, pass_fds = () cwd = None, env = None, universal_newlines = None, startupinfo = None creationflags = 0, shell = False, p2cread = -1, p2cwrite = -1, c2pread = 11 c2pwrite = 81, errread = 82, errwrite = 83, restore_signals = True, gid = None gids = None, uid = None, umask = -1, start_new_session = False process_group = None def _execute_child(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, universal_newlines, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, restore_signals, gid, gids, uid, umask, start_new_session, process_group): """Execute program (POSIX version)""" if isinstance(args, (str, bytes)): args = [args] elif isinstance(args, PathLike): if shell: raise TypeError('path-like args is not allowed when ' 'shell is true') args = [fsencode(args)] # os.PathLike -> [str] else: args = list(args) if shell: # On Android the default shell is at '/system/bin/sh'. unix_shell = ( '/system/bin/sh' if hasattr(sys, 'getandroidapilevel') else '/bin/sh' ) args = [unix_shell, "-c"] + args if executable: args[0] = executable if executable is None: executable = args[0] self._loop.install_sigchld() # For transferring possible exec failure from child to parent # The first char specifies the exception type: 0 means # OSError, 1 means some other error. errpipe_read, errpipe_write = self.pipe_cloexec() # errpipe_write must not be in the standard io 0, 1, or 2 fd range. low_fds_to_close = [] while errpipe_write < 3: low_fds_to_close.append(errpipe_write) errpipe_write = os.dup(errpipe_write) for low_fd in low_fds_to_close: os.close(low_fd) try: try: gc_was_enabled = gc.isenabled() # Disable gc to avoid bug where gc -> file_dealloc -> # write to stderr -> hang. http://bugs.python.org/issue1336 gc.disable() try: self.pid = fork_and_watch(self._on_child, self._loop, True, fork) except: if gc_was_enabled: gc.enable() raise if self.pid == 0: # Child # In various places on the child side of things, we catch OSError # and add attributes to it that detail where in the process we failed; # like all exceptions until we have exec'd, this exception is pickled # and sent to the parent to raise in the calling process. # The parent uses this to decide how to treat that exception, # adjusting certain information about it as needed. # # Python 3.11.8 --- yes, a minor patch release --- stopped # letting the 'filename' parameter get set in the resulting # exception for many cases. We're not quite interpreting this # the same way the stdlib is, I'm sure, but this makes the stdlib # tests pass. # XXX: Technically we're doing a lot of stuff here that # may not be safe to do before a exec(), depending on the OS. # CPython 3 goes to great lengths to precompute a lot # of this info before the fork and pass it all to C functions that # try hard not to call things like malloc(). (Of course, # CPython 2 pretty much did what we're doing.) try: # Close parent's pipe ends if p2cwrite != -1: os.close(p2cwrite) if c2pread != -1: os.close(c2pread) if errread != -1: os.close(errread) os.close(errpipe_read) # When duping fds, if there arises a situation # where one of the fds is either 0, 1 or 2, it # is possible that it is overwritten (#12607). if c2pwrite == 0: c2pwrite = os.dup(c2pwrite) _set_inheritable(c2pwrite, False) while errwrite in (0, 1): errwrite = os.dup(errwrite) _set_inheritable(errwrite, False) # Dup fds for child def _dup2(existing, desired): # dup2() removes the CLOEXEC flag but # we must do it ourselves if dup2() # would be a no-op (issue #10806). if existing == desired: self._set_cloexec_flag(existing, False) elif existing != -1: os.dup2(existing, desired) try: self._remove_nonblock_flag(desired) except OSError: # Ignore EBADF, it may not actually be # open yet. # Tested beginning in 3.7.0b3 test_subprocess.py pass _dup2(p2cread, 0) _dup2(c2pwrite, 1) _dup2(errwrite, 2) # Close pipe fds. Make sure we don't close the # same fd more than once, or standard fds. if not True: closed = set([None]) for fd in (p2cread, c2pwrite, errwrite): if fd not in closed and fd > 2: os.close(fd) closed.add(fd) # Python 3 (with a working set_inheritable): # We no longer manually close p2cread, # c2pwrite, and errwrite here as # _close_open_fds takes care when it is # not already non-inheritable. if cwd is not None: try: os.chdir(cwd) except OSError as e: e._failed_chdir = True raise # Python 3.9 if umask >= 0: os.umask(umask) # XXX: CPython does _Py_RestoreSignals here. # Then setsid() based on ??? try: if gids: os.setgroups(gids) if gid: os.setregid(gid, gid) if uid: os.setreuid(uid, uid) if process_group is not None: os.setpgid(0, process_group) except OSError as e: e._failed_chuser = True raise if preexec_fn: preexec_fn() # Close all other fds, if asked for. This must be done # after preexec_fn runs. if close_fds: fds_to_keep = set(pass_fds) fds_to_keep.add(errpipe_write) self._close_fds(fds_to_keep, errpipe_write) if restore_signals: # restore the documented signals back to sig_dfl; # not all will be defined on every platform for sig in 'SIGPIPE', 'SIGXFZ', 'SIGXFSZ': sig = getattr(signal, sig, None) if sig is not None: signal.signal(sig, signal.SIG_DFL) if start_new_session: os.setsid() try: if env is None: os.execvp(executable, args) else: # Python 3.6 started testing for # bytes values in the env; it also # started encoding strs using # fsencode and using a lower-level # API that takes a list of keys # and values. We don't have access # to that API, so we go the reverse direction. env = {os.fsdecode(k) if isinstance(k, bytes) else k: os.fsdecode(v) if isinstance(v, bytes) else v for k, v in env.items()} os.execvpe(executable, args, env) except OSError as e: e._failed_exec = True raise except: exc_type, exc_value, tb = sys.exc_info() # Save the traceback and attach it to the exception object exc_lines = traceback.format_exception(exc_type, exc_value, tb) exc_value.child_traceback = ''.join(exc_lines) os.write(errpipe_write, pickle.dumps(exc_value)) finally: # Make sure that the process exits no matter what. # The return code does not matter much as it won't be # reported to the application os._exit(1) # Parent self._child_created = True if gc_was_enabled: gc.enable() finally: # be sure the FD is closed no matter what os.close(errpipe_write) # self._devnull is not always defined. devnull_fd = getattr(self, '_devnull', None) if p2cread != -1 and p2cwrite != -1 and p2cread != devnull_fd: os.close(p2cread) if c2pwrite != -1 and c2pread != -1 and c2pwrite != devnull_fd: os.close(c2pwrite) if errwrite != -1 and errread != -1 and errwrite != devnull_fd: os.close(errwrite) if devnull_fd is not None: os.close(devnull_fd) # Prevent a double close of these fds from __init__ on error. self._closed_child_pipe_fds = True # Wait for exec to fail or succeed; possibly raising exception errpipe_read = FileObject(errpipe_read, 'rb') data = errpipe_read.read() finally: try: if hasattr(errpipe_read, 'close'): errpipe_read.close() else: os.close(errpipe_read) except OSError: # Especially on PyPy, we sometimes see the above # `os.close(errpipe_read)` raise an OSError. # It's not entirely clear why, but it happens in # InterprocessSignalTests.test_main sometimes, which must mean # we have some sort of race condition. pass finally: errpipe_read = -1 if data != b"": self.wait() child_exception = pickle.loads(data) for fd in (p2cwrite, c2pread, errread): if fd is not None and fd != -1: os.close(fd) if isinstance(child_exception, OSError): child_exception.filename = executable if hasattr(child_exception, '_failed_chdir'): child_exception.filename = cwd if getattr(child_exception, '_failed_chuser', False): child_exception.filename = None > raise child_exception E OSError: [Errno 8] Exec format error: 'locust' /usr/lib/python3/dist-packages/gevent/subprocess.py:1838: OSError _ DistributedIntegrationTests.test_distributed_with_locustfile_distribution_not_plain_filename _ self = def test_distributed_with_locustfile_distribution_not_plain_filename(self): LOCUSTFILE_CONTENT = textwrap.dedent( """ from locust import User, task, constant class User1(User): wait_time = constant(1) @task def t(self): pass """ ) with mock_locustfile(content=LOCUSTFILE_CONTENT) as mocked: > proc = subprocess.Popen( [ "locust", "-f", mocked.file_path[:-3], # remove ".py" "--headless", "--master", ], stderr=STDOUT, stdout=PIPE, text=True, ) locust/test/test_main.py:1804: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3/dist-packages/gevent/subprocess.py:808: in __init__ self._execute_child(args, executable, preexec_fn, close_fds, _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = args = ['locust', '-f', '/build/reproducible-path/locust-2.24.0/locust/test/mock_locustfile_1715256387_6424901_59027', '--headless', '--master'] executable = 'locust', preexec_fn = None, close_fds = True, pass_fds = () cwd = None, env = None, universal_newlines = None, startupinfo = None creationflags = 0, shell = False, p2cread = -1, p2cwrite = -1, c2pread = 11 c2pwrite = 81, errread = -1, errwrite = 81, restore_signals = True, gid = None gids = None, uid = None, umask = -1, start_new_session = False process_group = None def _execute_child(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, universal_newlines, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, restore_signals, gid, gids, uid, umask, start_new_session, process_group): """Execute program (POSIX version)""" if isinstance(args, (str, bytes)): args = [args] elif isinstance(args, PathLike): if shell: raise TypeError('path-like args is not allowed when ' 'shell is true') args = [fsencode(args)] # os.PathLike -> [str] else: args = list(args) if shell: # On Android the default shell is at '/system/bin/sh'. unix_shell = ( '/system/bin/sh' if hasattr(sys, 'getandroidapilevel') else '/bin/sh' ) args = [unix_shell, "-c"] + args if executable: args[0] = executable if executable is None: executable = args[0] self._loop.install_sigchld() # For transferring possible exec failure from child to parent # The first char specifies the exception type: 0 means # OSError, 1 means some other error. errpipe_read, errpipe_write = self.pipe_cloexec() # errpipe_write must not be in the standard io 0, 1, or 2 fd range. low_fds_to_close = [] while errpipe_write < 3: low_fds_to_close.append(errpipe_write) errpipe_write = os.dup(errpipe_write) for low_fd in low_fds_to_close: os.close(low_fd) try: try: gc_was_enabled = gc.isenabled() # Disable gc to avoid bug where gc -> file_dealloc -> # write to stderr -> hang. http://bugs.python.org/issue1336 gc.disable() try: self.pid = fork_and_watch(self._on_child, self._loop, True, fork) except: if gc_was_enabled: gc.enable() raise if self.pid == 0: # Child # In various places on the child side of things, we catch OSError # and add attributes to it that detail where in the process we failed; # like all exceptions until we have exec'd, this exception is pickled # and sent to the parent to raise in the calling process. # The parent uses this to decide how to treat that exception, # adjusting certain information about it as needed. # # Python 3.11.8 --- yes, a minor patch release --- stopped # letting the 'filename' parameter get set in the resulting # exception for many cases. We're not quite interpreting this # the same way the stdlib is, I'm sure, but this makes the stdlib # tests pass. # XXX: Technically we're doing a lot of stuff here that # may not be safe to do before a exec(), depending on the OS. # CPython 3 goes to great lengths to precompute a lot # of this info before the fork and pass it all to C functions that # try hard not to call things like malloc(). (Of course, # CPython 2 pretty much did what we're doing.) try: # Close parent's pipe ends if p2cwrite != -1: os.close(p2cwrite) if c2pread != -1: os.close(c2pread) if errread != -1: os.close(errread) os.close(errpipe_read) # When duping fds, if there arises a situation # where one of the fds is either 0, 1 or 2, it # is possible that it is overwritten (#12607). if c2pwrite == 0: c2pwrite = os.dup(c2pwrite) _set_inheritable(c2pwrite, False) while errwrite in (0, 1): errwrite = os.dup(errwrite) _set_inheritable(errwrite, False) # Dup fds for child def _dup2(existing, desired): # dup2() removes the CLOEXEC flag but # we must do it ourselves if dup2() # would be a no-op (issue #10806). if existing == desired: self._set_cloexec_flag(existing, False) elif existing != -1: os.dup2(existing, desired) try: self._remove_nonblock_flag(desired) except OSError: # Ignore EBADF, it may not actually be # open yet. # Tested beginning in 3.7.0b3 test_subprocess.py pass _dup2(p2cread, 0) _dup2(c2pwrite, 1) _dup2(errwrite, 2) # Close pipe fds. Make sure we don't close the # same fd more than once, or standard fds. if not True: closed = set([None]) for fd in (p2cread, c2pwrite, errwrite): if fd not in closed and fd > 2: os.close(fd) closed.add(fd) # Python 3 (with a working set_inheritable): # We no longer manually close p2cread, # c2pwrite, and errwrite here as # _close_open_fds takes care when it is # not already non-inheritable. if cwd is not None: try: os.chdir(cwd) except OSError as e: e._failed_chdir = True raise # Python 3.9 if umask >= 0: os.umask(umask) # XXX: CPython does _Py_RestoreSignals here. # Then setsid() based on ??? try: if gids: os.setgroups(gids) if gid: os.setregid(gid, gid) if uid: os.setreuid(uid, uid) if process_group is not None: os.setpgid(0, process_group) except OSError as e: e._failed_chuser = True raise if preexec_fn: preexec_fn() # Close all other fds, if asked for. This must be done # after preexec_fn runs. if close_fds: fds_to_keep = set(pass_fds) fds_to_keep.add(errpipe_write) self._close_fds(fds_to_keep, errpipe_write) if restore_signals: # restore the documented signals back to sig_dfl; # not all will be defined on every platform for sig in 'SIGPIPE', 'SIGXFZ', 'SIGXFSZ': sig = getattr(signal, sig, None) if sig is not None: signal.signal(sig, signal.SIG_DFL) if start_new_session: os.setsid() try: if env is None: os.execvp(executable, args) else: # Python 3.6 started testing for # bytes values in the env; it also # started encoding strs using # fsencode and using a lower-level # API that takes a list of keys # and values. We don't have access # to that API, so we go the reverse direction. env = {os.fsdecode(k) if isinstance(k, bytes) else k: os.fsdecode(v) if isinstance(v, bytes) else v for k, v in env.items()} os.execvpe(executable, args, env) except OSError as e: e._failed_exec = True raise except: exc_type, exc_value, tb = sys.exc_info() # Save the traceback and attach it to the exception object exc_lines = traceback.format_exception(exc_type, exc_value, tb) exc_value.child_traceback = ''.join(exc_lines) os.write(errpipe_write, pickle.dumps(exc_value)) finally: # Make sure that the process exits no matter what. # The return code does not matter much as it won't be # reported to the application os._exit(1) # Parent self._child_created = True if gc_was_enabled: gc.enable() finally: # be sure the FD is closed no matter what os.close(errpipe_write) # self._devnull is not always defined. devnull_fd = getattr(self, '_devnull', None) if p2cread != -1 and p2cwrite != -1 and p2cread != devnull_fd: os.close(p2cread) if c2pwrite != -1 and c2pread != -1 and c2pwrite != devnull_fd: os.close(c2pwrite) if errwrite != -1 and errread != -1 and errwrite != devnull_fd: os.close(errwrite) if devnull_fd is not None: os.close(devnull_fd) # Prevent a double close of these fds from __init__ on error. self._closed_child_pipe_fds = True # Wait for exec to fail or succeed; possibly raising exception errpipe_read = FileObject(errpipe_read, 'rb') data = errpipe_read.read() finally: try: if hasattr(errpipe_read, 'close'): errpipe_read.close() else: os.close(errpipe_read) except OSError: # Especially on PyPy, we sometimes see the above # `os.close(errpipe_read)` raise an OSError. # It's not entirely clear why, but it happens in # InterprocessSignalTests.test_main sometimes, which must mean # we have some sort of race condition. pass finally: errpipe_read = -1 if data != b"": self.wait() child_exception = pickle.loads(data) for fd in (p2cwrite, c2pread, errread): if fd is not None and fd != -1: os.close(fd) if isinstance(child_exception, OSError): child_exception.filename = executable if hasattr(child_exception, '_failed_chdir'): child_exception.filename = cwd if getattr(child_exception, '_failed_chuser', False): child_exception.filename = None > raise child_exception E OSError: [Errno 8] Exec format error: 'locust' /usr/lib/python3/dist-packages/gevent/subprocess.py:1838: OSError _______________ DistributedIntegrationTests.test_expect_workers ________________ self = def test_expect_workers(self): with mock_locustfile() as mocked: > proc = subprocess.Popen( [ "locust", "-f", mocked.file_path, "--headless", "--master", "--expect-workers", "2", "--expect-workers-max-wait", "1", ], stdout=PIPE, stderr=PIPE, text=True, ) locust/test/test_main.py:1404: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3/dist-packages/gevent/subprocess.py:808: in __init__ self._execute_child(args, executable, preexec_fn, close_fds, _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = args = ['locust', '-f', '/build/reproducible-path/locust-2.24.0/locust/test/mock_locustfile_1715256387_8341706_81846.py', '--headless', '--master', '--expect-workers', ...] executable = 'locust', preexec_fn = None, close_fds = True, pass_fds = () cwd = None, env = None, universal_newlines = None, startupinfo = None creationflags = 0, shell = False, p2cread = -1, p2cwrite = -1, c2pread = 11 c2pwrite = 81, errread = 82, errwrite = 83, restore_signals = True, gid = None gids = None, uid = None, umask = -1, start_new_session = False process_group = None def _execute_child(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, universal_newlines, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, restore_signals, gid, gids, uid, umask, start_new_session, process_group): """Execute program (POSIX version)""" if isinstance(args, (str, bytes)): args = [args] elif isinstance(args, PathLike): if shell: raise TypeError('path-like args is not allowed when ' 'shell is true') args = [fsencode(args)] # os.PathLike -> [str] else: args = list(args) if shell: # On Android the default shell is at '/system/bin/sh'. unix_shell = ( '/system/bin/sh' if hasattr(sys, 'getandroidapilevel') else '/bin/sh' ) args = [unix_shell, "-c"] + args if executable: args[0] = executable if executable is None: executable = args[0] self._loop.install_sigchld() # For transferring possible exec failure from child to parent # The first char specifies the exception type: 0 means # OSError, 1 means some other error. errpipe_read, errpipe_write = self.pipe_cloexec() # errpipe_write must not be in the standard io 0, 1, or 2 fd range. low_fds_to_close = [] while errpipe_write < 3: low_fds_to_close.append(errpipe_write) errpipe_write = os.dup(errpipe_write) for low_fd in low_fds_to_close: os.close(low_fd) try: try: gc_was_enabled = gc.isenabled() # Disable gc to avoid bug where gc -> file_dealloc -> # write to stderr -> hang. http://bugs.python.org/issue1336 gc.disable() try: self.pid = fork_and_watch(self._on_child, self._loop, True, fork) except: if gc_was_enabled: gc.enable() raise if self.pid == 0: # Child # In various places on the child side of things, we catch OSError # and add attributes to it that detail where in the process we failed; # like all exceptions until we have exec'd, this exception is pickled # and sent to the parent to raise in the calling process. # The parent uses this to decide how to treat that exception, # adjusting certain information about it as needed. # # Python 3.11.8 --- yes, a minor patch release --- stopped # letting the 'filename' parameter get set in the resulting # exception for many cases. We're not quite interpreting this # the same way the stdlib is, I'm sure, but this makes the stdlib # tests pass. # XXX: Technically we're doing a lot of stuff here that # may not be safe to do before a exec(), depending on the OS. # CPython 3 goes to great lengths to precompute a lot # of this info before the fork and pass it all to C functions that # try hard not to call things like malloc(). (Of course, # CPython 2 pretty much did what we're doing.) try: # Close parent's pipe ends if p2cwrite != -1: os.close(p2cwrite) if c2pread != -1: os.close(c2pread) if errread != -1: os.close(errread) os.close(errpipe_read) # When duping fds, if there arises a situation # where one of the fds is either 0, 1 or 2, it # is possible that it is overwritten (#12607). if c2pwrite == 0: c2pwrite = os.dup(c2pwrite) _set_inheritable(c2pwrite, False) while errwrite in (0, 1): errwrite = os.dup(errwrite) _set_inheritable(errwrite, False) # Dup fds for child def _dup2(existing, desired): # dup2() removes the CLOEXEC flag but # we must do it ourselves if dup2() # would be a no-op (issue #10806). if existing == desired: self._set_cloexec_flag(existing, False) elif existing != -1: os.dup2(existing, desired) try: self._remove_nonblock_flag(desired) except OSError: # Ignore EBADF, it may not actually be # open yet. # Tested beginning in 3.7.0b3 test_subprocess.py pass _dup2(p2cread, 0) _dup2(c2pwrite, 1) _dup2(errwrite, 2) # Close pipe fds. Make sure we don't close the # same fd more than once, or standard fds. if not True: closed = set([None]) for fd in (p2cread, c2pwrite, errwrite): if fd not in closed and fd > 2: os.close(fd) closed.add(fd) # Python 3 (with a working set_inheritable): # We no longer manually close p2cread, # c2pwrite, and errwrite here as # _close_open_fds takes care when it is # not already non-inheritable. if cwd is not None: try: os.chdir(cwd) except OSError as e: e._failed_chdir = True raise # Python 3.9 if umask >= 0: os.umask(umask) # XXX: CPython does _Py_RestoreSignals here. # Then setsid() based on ??? try: if gids: os.setgroups(gids) if gid: os.setregid(gid, gid) if uid: os.setreuid(uid, uid) if process_group is not None: os.setpgid(0, process_group) except OSError as e: e._failed_chuser = True raise if preexec_fn: preexec_fn() # Close all other fds, if asked for. This must be done # after preexec_fn runs. if close_fds: fds_to_keep = set(pass_fds) fds_to_keep.add(errpipe_write) self._close_fds(fds_to_keep, errpipe_write) if restore_signals: # restore the documented signals back to sig_dfl; # not all will be defined on every platform for sig in 'SIGPIPE', 'SIGXFZ', 'SIGXFSZ': sig = getattr(signal, sig, None) if sig is not None: signal.signal(sig, signal.SIG_DFL) if start_new_session: os.setsid() try: if env is None: os.execvp(executable, args) else: # Python 3.6 started testing for # bytes values in the env; it also # started encoding strs using # fsencode and using a lower-level # API that takes a list of keys # and values. We don't have access # to that API, so we go the reverse direction. env = {os.fsdecode(k) if isinstance(k, bytes) else k: os.fsdecode(v) if isinstance(v, bytes) else v for k, v in env.items()} os.execvpe(executable, args, env) except OSError as e: e._failed_exec = True raise except: exc_type, exc_value, tb = sys.exc_info() # Save the traceback and attach it to the exception object exc_lines = traceback.format_exception(exc_type, exc_value, tb) exc_value.child_traceback = ''.join(exc_lines) os.write(errpipe_write, pickle.dumps(exc_value)) finally: # Make sure that the process exits no matter what. # The return code does not matter much as it won't be # reported to the application os._exit(1) # Parent self._child_created = True if gc_was_enabled: gc.enable() finally: # be sure the FD is closed no matter what os.close(errpipe_write) # self._devnull is not always defined. devnull_fd = getattr(self, '_devnull', None) if p2cread != -1 and p2cwrite != -1 and p2cread != devnull_fd: os.close(p2cread) if c2pwrite != -1 and c2pread != -1 and c2pwrite != devnull_fd: os.close(c2pwrite) if errwrite != -1 and errread != -1 and errwrite != devnull_fd: os.close(errwrite) if devnull_fd is not None: os.close(devnull_fd) # Prevent a double close of these fds from __init__ on error. self._closed_child_pipe_fds = True # Wait for exec to fail or succeed; possibly raising exception errpipe_read = FileObject(errpipe_read, 'rb') data = errpipe_read.read() finally: try: if hasattr(errpipe_read, 'close'): errpipe_read.close() else: os.close(errpipe_read) except OSError: # Especially on PyPy, we sometimes see the above # `os.close(errpipe_read)` raise an OSError. # It's not entirely clear why, but it happens in # InterprocessSignalTests.test_main sometimes, which must mean # we have some sort of race condition. pass finally: errpipe_read = -1 if data != b"": self.wait() child_exception = pickle.loads(data) for fd in (p2cwrite, c2pread, errread): if fd is not None and fd != -1: os.close(fd) if isinstance(child_exception, OSError): child_exception.filename = executable if hasattr(child_exception, '_failed_chdir'): child_exception.filename = cwd if getattr(child_exception, '_failed_chuser', False): child_exception.filename = None > raise child_exception E OSError: [Errno 8] Exec format error: 'locust' /usr/lib/python3/dist-packages/gevent/subprocess.py:1838: OSError _________________ DistributedIntegrationTests.test_json_schema _________________ self = def test_json_schema(self): LOCUSTFILE_CONTENT = textwrap.dedent( """ from locust import HttpUser, task, constant class QuickstartUser(HttpUser): wait_time = constant(1) @task def hello_world(self): self.client.get("/") """ ) with mock_locustfile(content=LOCUSTFILE_CONTENT) as mocked: > proc = subprocess.Popen( [ "locust", "-f", mocked.file_path, "--host", "http://google.com", "--headless", "-u", "1", "-t", "2s", "--json", ], stderr=DEVNULL, stdout=PIPE, text=True, ) locust/test/test_main.py:1848: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3/dist-packages/gevent/subprocess.py:808: in __init__ self._execute_child(args, executable, preexec_fn, close_fds, _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = args = ['locust', '-f', '/build/reproducible-path/locust-2.24.0/locust/test/mock_locustfile_1715256388_0840864_55210.py', '--host', 'http://google.com', '--headless', ...] executable = 'locust', preexec_fn = None, close_fds = True, pass_fds = () cwd = None, env = None, universal_newlines = None, startupinfo = None creationflags = 0, shell = False, p2cread = -1, p2cwrite = -1, c2pread = 11 c2pwrite = 81, errread = -1, errwrite = 82, restore_signals = True, gid = None gids = None, uid = None, umask = -1, start_new_session = False process_group = None def _execute_child(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, universal_newlines, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, restore_signals, gid, gids, uid, umask, start_new_session, process_group): """Execute program (POSIX version)""" if isinstance(args, (str, bytes)): args = [args] elif isinstance(args, PathLike): if shell: raise TypeError('path-like args is not allowed when ' 'shell is true') args = [fsencode(args)] # os.PathLike -> [str] else: args = list(args) if shell: # On Android the default shell is at '/system/bin/sh'. unix_shell = ( '/system/bin/sh' if hasattr(sys, 'getandroidapilevel') else '/bin/sh' ) args = [unix_shell, "-c"] + args if executable: args[0] = executable if executable is None: executable = args[0] self._loop.install_sigchld() # For transferring possible exec failure from child to parent # The first char specifies the exception type: 0 means # OSError, 1 means some other error. errpipe_read, errpipe_write = self.pipe_cloexec() # errpipe_write must not be in the standard io 0, 1, or 2 fd range. low_fds_to_close = [] while errpipe_write < 3: low_fds_to_close.append(errpipe_write) errpipe_write = os.dup(errpipe_write) for low_fd in low_fds_to_close: os.close(low_fd) try: try: gc_was_enabled = gc.isenabled() # Disable gc to avoid bug where gc -> file_dealloc -> # write to stderr -> hang. http://bugs.python.org/issue1336 gc.disable() try: self.pid = fork_and_watch(self._on_child, self._loop, True, fork) except: if gc_was_enabled: gc.enable() raise if self.pid == 0: # Child # In various places on the child side of things, we catch OSError # and add attributes to it that detail where in the process we failed; # like all exceptions until we have exec'd, this exception is pickled # and sent to the parent to raise in the calling process. # The parent uses this to decide how to treat that exception, # adjusting certain information about it as needed. # # Python 3.11.8 --- yes, a minor patch release --- stopped # letting the 'filename' parameter get set in the resulting # exception for many cases. We're not quite interpreting this # the same way the stdlib is, I'm sure, but this makes the stdlib # tests pass. # XXX: Technically we're doing a lot of stuff here that # may not be safe to do before a exec(), depending on the OS. # CPython 3 goes to great lengths to precompute a lot # of this info before the fork and pass it all to C functions that # try hard not to call things like malloc(). (Of course, # CPython 2 pretty much did what we're doing.) try: # Close parent's pipe ends if p2cwrite != -1: os.close(p2cwrite) if c2pread != -1: os.close(c2pread) if errread != -1: os.close(errread) os.close(errpipe_read) # When duping fds, if there arises a situation # where one of the fds is either 0, 1 or 2, it # is possible that it is overwritten (#12607). if c2pwrite == 0: c2pwrite = os.dup(c2pwrite) _set_inheritable(c2pwrite, False) while errwrite in (0, 1): errwrite = os.dup(errwrite) _set_inheritable(errwrite, False) # Dup fds for child def _dup2(existing, desired): # dup2() removes the CLOEXEC flag but # we must do it ourselves if dup2() # would be a no-op (issue #10806). if existing == desired: self._set_cloexec_flag(existing, False) elif existing != -1: os.dup2(existing, desired) try: self._remove_nonblock_flag(desired) except OSError: # Ignore EBADF, it may not actually be # open yet. # Tested beginning in 3.7.0b3 test_subprocess.py pass _dup2(p2cread, 0) _dup2(c2pwrite, 1) _dup2(errwrite, 2) # Close pipe fds. Make sure we don't close the # same fd more than once, or standard fds. if not True: closed = set([None]) for fd in (p2cread, c2pwrite, errwrite): if fd not in closed and fd > 2: os.close(fd) closed.add(fd) # Python 3 (with a working set_inheritable): # We no longer manually close p2cread, # c2pwrite, and errwrite here as # _close_open_fds takes care when it is # not already non-inheritable. if cwd is not None: try: os.chdir(cwd) except OSError as e: e._failed_chdir = True raise # Python 3.9 if umask >= 0: os.umask(umask) # XXX: CPython does _Py_RestoreSignals here. # Then setsid() based on ??? try: if gids: os.setgroups(gids) if gid: os.setregid(gid, gid) if uid: os.setreuid(uid, uid) if process_group is not None: os.setpgid(0, process_group) except OSError as e: e._failed_chuser = True raise if preexec_fn: preexec_fn() # Close all other fds, if asked for. This must be done # after preexec_fn runs. if close_fds: fds_to_keep = set(pass_fds) fds_to_keep.add(errpipe_write) self._close_fds(fds_to_keep, errpipe_write) if restore_signals: # restore the documented signals back to sig_dfl; # not all will be defined on every platform for sig in 'SIGPIPE', 'SIGXFZ', 'SIGXFSZ': sig = getattr(signal, sig, None) if sig is not None: signal.signal(sig, signal.SIG_DFL) if start_new_session: os.setsid() try: if env is None: os.execvp(executable, args) else: # Python 3.6 started testing for # bytes values in the env; it also # started encoding strs using # fsencode and using a lower-level # API that takes a list of keys # and values. We don't have access # to that API, so we go the reverse direction. env = {os.fsdecode(k) if isinstance(k, bytes) else k: os.fsdecode(v) if isinstance(v, bytes) else v for k, v in env.items()} os.execvpe(executable, args, env) except OSError as e: e._failed_exec = True raise except: exc_type, exc_value, tb = sys.exc_info() # Save the traceback and attach it to the exception object exc_lines = traceback.format_exception(exc_type, exc_value, tb) exc_value.child_traceback = ''.join(exc_lines) os.write(errpipe_write, pickle.dumps(exc_value)) finally: # Make sure that the process exits no matter what. # The return code does not matter much as it won't be # reported to the application os._exit(1) # Parent self._child_created = True if gc_was_enabled: gc.enable() finally: # be sure the FD is closed no matter what os.close(errpipe_write) # self._devnull is not always defined. devnull_fd = getattr(self, '_devnull', None) if p2cread != -1 and p2cwrite != -1 and p2cread != devnull_fd: os.close(p2cread) if c2pwrite != -1 and c2pread != -1 and c2pwrite != devnull_fd: os.close(c2pwrite) if errwrite != -1 and errread != -1 and errwrite != devnull_fd: os.close(errwrite) if devnull_fd is not None: os.close(devnull_fd) # Prevent a double close of these fds from __init__ on error. self._closed_child_pipe_fds = True # Wait for exec to fail or succeed; possibly raising exception errpipe_read = FileObject(errpipe_read, 'rb') data = errpipe_read.read() finally: try: if hasattr(errpipe_read, 'close'): errpipe_read.close() else: os.close(errpipe_read) except OSError: # Especially on PyPy, we sometimes see the above # `os.close(errpipe_read)` raise an OSError. # It's not entirely clear why, but it happens in # InterprocessSignalTests.test_main sometimes, which must mean # we have some sort of race condition. pass finally: errpipe_read = -1 if data != b"": self.wait() child_exception = pickle.loads(data) for fd in (p2cwrite, c2pread, errread): if fd is not None and fd != -1: os.close(fd) if isinstance(child_exception, OSError): child_exception.filename = executable if hasattr(child_exception, '_failed_chdir'): child_exception.filename = cwd if getattr(child_exception, '_failed_chuser', False): child_exception.filename = None > raise child_exception E OSError: [Errno 8] Exec format error: 'locust' /usr/lib/python3/dist-packages/gevent/subprocess.py:1838: OSError ___________ DistributedIntegrationTests.test_locustfile_distribution ___________ self = def test_locustfile_distribution(self): LOCUSTFILE_CONTENT = textwrap.dedent( """ from locust import User, task, constant class User1(User): wait_time = constant(1) @task def t(self): pass """ ) with mock_locustfile(content=LOCUSTFILE_CONTENT) as mocked: > proc = subprocess.Popen( [ "locust", "-f", mocked.file_path, "--headless", "--master", "--expect-workers", "2", "-t", "1s", ], stderr=STDOUT, stdout=PIPE, text=True, ) locust/test/test_main.py:1679: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3/dist-packages/gevent/subprocess.py:808: in __init__ self._execute_child(args, executable, preexec_fn, close_fds, _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = args = ['locust', '-f', '/build/reproducible-path/locust-2.24.0/locust/test/mock_locustfile_1715256388_2080586_39531.py', '--headless', '--master', '--expect-workers', ...] executable = 'locust', preexec_fn = None, close_fds = True, pass_fds = () cwd = None, env = None, universal_newlines = None, startupinfo = None creationflags = 0, shell = False, p2cread = -1, p2cwrite = -1, c2pread = 11 c2pwrite = 81, errread = -1, errwrite = 81, restore_signals = True, gid = None gids = None, uid = None, umask = -1, start_new_session = False process_group = None def _execute_child(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, universal_newlines, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, restore_signals, gid, gids, uid, umask, start_new_session, process_group): """Execute program (POSIX version)""" if isinstance(args, (str, bytes)): args = [args] elif isinstance(args, PathLike): if shell: raise TypeError('path-like args is not allowed when ' 'shell is true') args = [fsencode(args)] # os.PathLike -> [str] else: args = list(args) if shell: # On Android the default shell is at '/system/bin/sh'. unix_shell = ( '/system/bin/sh' if hasattr(sys, 'getandroidapilevel') else '/bin/sh' ) args = [unix_shell, "-c"] + args if executable: args[0] = executable if executable is None: executable = args[0] self._loop.install_sigchld() # For transferring possible exec failure from child to parent # The first char specifies the exception type: 0 means # OSError, 1 means some other error. errpipe_read, errpipe_write = self.pipe_cloexec() # errpipe_write must not be in the standard io 0, 1, or 2 fd range. low_fds_to_close = [] while errpipe_write < 3: low_fds_to_close.append(errpipe_write) errpipe_write = os.dup(errpipe_write) for low_fd in low_fds_to_close: os.close(low_fd) try: try: gc_was_enabled = gc.isenabled() # Disable gc to avoid bug where gc -> file_dealloc -> # write to stderr -> hang. http://bugs.python.org/issue1336 gc.disable() try: self.pid = fork_and_watch(self._on_child, self._loop, True, fork) except: if gc_was_enabled: gc.enable() raise if self.pid == 0: # Child # In various places on the child side of things, we catch OSError # and add attributes to it that detail where in the process we failed; # like all exceptions until we have exec'd, this exception is pickled # and sent to the parent to raise in the calling process. # The parent uses this to decide how to treat that exception, # adjusting certain information about it as needed. # # Python 3.11.8 --- yes, a minor patch release --- stopped # letting the 'filename' parameter get set in the resulting # exception for many cases. We're not quite interpreting this # the same way the stdlib is, I'm sure, but this makes the stdlib # tests pass. # XXX: Technically we're doing a lot of stuff here that # may not be safe to do before a exec(), depending on the OS. # CPython 3 goes to great lengths to precompute a lot # of this info before the fork and pass it all to C functions that # try hard not to call things like malloc(). (Of course, # CPython 2 pretty much did what we're doing.) try: # Close parent's pipe ends if p2cwrite != -1: os.close(p2cwrite) if c2pread != -1: os.close(c2pread) if errread != -1: os.close(errread) os.close(errpipe_read) # When duping fds, if there arises a situation # where one of the fds is either 0, 1 or 2, it # is possible that it is overwritten (#12607). if c2pwrite == 0: c2pwrite = os.dup(c2pwrite) _set_inheritable(c2pwrite, False) while errwrite in (0, 1): errwrite = os.dup(errwrite) _set_inheritable(errwrite, False) # Dup fds for child def _dup2(existing, desired): # dup2() removes the CLOEXEC flag but # we must do it ourselves if dup2() # would be a no-op (issue #10806). if existing == desired: self._set_cloexec_flag(existing, False) elif existing != -1: os.dup2(existing, desired) try: self._remove_nonblock_flag(desired) except OSError: # Ignore EBADF, it may not actually be # open yet. # Tested beginning in 3.7.0b3 test_subprocess.py pass _dup2(p2cread, 0) _dup2(c2pwrite, 1) _dup2(errwrite, 2) # Close pipe fds. Make sure we don't close the # same fd more than once, or standard fds. if not True: closed = set([None]) for fd in (p2cread, c2pwrite, errwrite): if fd not in closed and fd > 2: os.close(fd) closed.add(fd) # Python 3 (with a working set_inheritable): # We no longer manually close p2cread, # c2pwrite, and errwrite here as # _close_open_fds takes care when it is # not already non-inheritable. if cwd is not None: try: os.chdir(cwd) except OSError as e: e._failed_chdir = True raise # Python 3.9 if umask >= 0: os.umask(umask) # XXX: CPython does _Py_RestoreSignals here. # Then setsid() based on ??? try: if gids: os.setgroups(gids) if gid: os.setregid(gid, gid) if uid: os.setreuid(uid, uid) if process_group is not None: os.setpgid(0, process_group) except OSError as e: e._failed_chuser = True raise if preexec_fn: preexec_fn() # Close all other fds, if asked for. This must be done # after preexec_fn runs. if close_fds: fds_to_keep = set(pass_fds) fds_to_keep.add(errpipe_write) self._close_fds(fds_to_keep, errpipe_write) if restore_signals: # restore the documented signals back to sig_dfl; # not all will be defined on every platform for sig in 'SIGPIPE', 'SIGXFZ', 'SIGXFSZ': sig = getattr(signal, sig, None) if sig is not None: signal.signal(sig, signal.SIG_DFL) if start_new_session: os.setsid() try: if env is None: os.execvp(executable, args) else: # Python 3.6 started testing for # bytes values in the env; it also # started encoding strs using # fsencode and using a lower-level # API that takes a list of keys # and values. We don't have access # to that API, so we go the reverse direction. env = {os.fsdecode(k) if isinstance(k, bytes) else k: os.fsdecode(v) if isinstance(v, bytes) else v for k, v in env.items()} os.execvpe(executable, args, env) except OSError as e: e._failed_exec = True raise except: exc_type, exc_value, tb = sys.exc_info() # Save the traceback and attach it to the exception object exc_lines = traceback.format_exception(exc_type, exc_value, tb) exc_value.child_traceback = ''.join(exc_lines) os.write(errpipe_write, pickle.dumps(exc_value)) finally: # Make sure that the process exits no matter what. # The return code does not matter much as it won't be # reported to the application os._exit(1) # Parent self._child_created = True if gc_was_enabled: gc.enable() finally: # be sure the FD is closed no matter what os.close(errpipe_write) # self._devnull is not always defined. devnull_fd = getattr(self, '_devnull', None) if p2cread != -1 and p2cwrite != -1 and p2cread != devnull_fd: os.close(p2cread) if c2pwrite != -1 and c2pread != -1 and c2pwrite != devnull_fd: os.close(c2pwrite) if errwrite != -1 and errread != -1 and errwrite != devnull_fd: os.close(errwrite) if devnull_fd is not None: os.close(devnull_fd) # Prevent a double close of these fds from __init__ on error. self._closed_child_pipe_fds = True # Wait for exec to fail or succeed; possibly raising exception errpipe_read = FileObject(errpipe_read, 'rb') data = errpipe_read.read() finally: try: if hasattr(errpipe_read, 'close'): errpipe_read.close() else: os.close(errpipe_read) except OSError: # Especially on PyPy, we sometimes see the above # `os.close(errpipe_read)` raise an OSError. # It's not entirely clear why, but it happens in # InterprocessSignalTests.test_main sometimes, which must mean # we have some sort of race condition. pass finally: errpipe_read = -1 if data != b"": self.wait() child_exception = pickle.loads(data) for fd in (p2cwrite, c2pread, errread): if fd is not None and fd != -1: os.close(fd) if isinstance(child_exception, OSError): child_exception.filename = executable if hasattr(child_exception, '_failed_chdir'): child_exception.filename = cwd if getattr(child_exception, '_failed_chuser', False): child_exception.filename = None > raise child_exception E OSError: [Errno 8] Exec format error: 'locust' /usr/lib/python3/dist-packages/gevent/subprocess.py:1838: OSError _ DistributedIntegrationTests.test_locustfile_distribution_with_workers_started_first _ self = def test_locustfile_distribution_with_workers_started_first(self): LOCUSTFILE_CONTENT = textwrap.dedent( """ from locust import User, task, constant class User1(User): wait_time = constant(1) @task def t(self): print("hello") """ ) with mock_locustfile(content=LOCUSTFILE_CONTENT) as mocked: > proc_worker = subprocess.Popen( [ "locust", "-f", "-", "--worker", ], stderr=STDOUT, stdout=PIPE, text=True, ) locust/test/test_main.py:1751: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3/dist-packages/gevent/subprocess.py:808: in __init__ self._execute_child(args, executable, preexec_fn, close_fds, _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = args = ['locust', '-f', '-', '--worker'], executable = 'locust' preexec_fn = None, close_fds = True, pass_fds = (), cwd = None, env = None universal_newlines = None, startupinfo = None, creationflags = 0, shell = False p2cread = -1, p2cwrite = -1, c2pread = 11, c2pwrite = 81, errread = -1 errwrite = 81, restore_signals = True, gid = None, gids = None, uid = None umask = -1, start_new_session = False, process_group = None def _execute_child(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, universal_newlines, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, restore_signals, gid, gids, uid, umask, start_new_session, process_group): """Execute program (POSIX version)""" if isinstance(args, (str, bytes)): args = [args] elif isinstance(args, PathLike): if shell: raise TypeError('path-like args is not allowed when ' 'shell is true') args = [fsencode(args)] # os.PathLike -> [str] else: args = list(args) if shell: # On Android the default shell is at '/system/bin/sh'. unix_shell = ( '/system/bin/sh' if hasattr(sys, 'getandroidapilevel') else '/bin/sh' ) args = [unix_shell, "-c"] + args if executable: args[0] = executable if executable is None: executable = args[0] self._loop.install_sigchld() # For transferring possible exec failure from child to parent # The first char specifies the exception type: 0 means # OSError, 1 means some other error. errpipe_read, errpipe_write = self.pipe_cloexec() # errpipe_write must not be in the standard io 0, 1, or 2 fd range. low_fds_to_close = [] while errpipe_write < 3: low_fds_to_close.append(errpipe_write) errpipe_write = os.dup(errpipe_write) for low_fd in low_fds_to_close: os.close(low_fd) try: try: gc_was_enabled = gc.isenabled() # Disable gc to avoid bug where gc -> file_dealloc -> # write to stderr -> hang. http://bugs.python.org/issue1336 gc.disable() try: self.pid = fork_and_watch(self._on_child, self._loop, True, fork) except: if gc_was_enabled: gc.enable() raise if self.pid == 0: # Child # In various places on the child side of things, we catch OSError # and add attributes to it that detail where in the process we failed; # like all exceptions until we have exec'd, this exception is pickled # and sent to the parent to raise in the calling process. # The parent uses this to decide how to treat that exception, # adjusting certain information about it as needed. # # Python 3.11.8 --- yes, a minor patch release --- stopped # letting the 'filename' parameter get set in the resulting # exception for many cases. We're not quite interpreting this # the same way the stdlib is, I'm sure, but this makes the stdlib # tests pass. # XXX: Technically we're doing a lot of stuff here that # may not be safe to do before a exec(), depending on the OS. # CPython 3 goes to great lengths to precompute a lot # of this info before the fork and pass it all to C functions that # try hard not to call things like malloc(). (Of course, # CPython 2 pretty much did what we're doing.) try: # Close parent's pipe ends if p2cwrite != -1: os.close(p2cwrite) if c2pread != -1: os.close(c2pread) if errread != -1: os.close(errread) os.close(errpipe_read) # When duping fds, if there arises a situation # where one of the fds is either 0, 1 or 2, it # is possible that it is overwritten (#12607). if c2pwrite == 0: c2pwrite = os.dup(c2pwrite) _set_inheritable(c2pwrite, False) while errwrite in (0, 1): errwrite = os.dup(errwrite) _set_inheritable(errwrite, False) # Dup fds for child def _dup2(existing, desired): # dup2() removes the CLOEXEC flag but # we must do it ourselves if dup2() # would be a no-op (issue #10806). if existing == desired: self._set_cloexec_flag(existing, False) elif existing != -1: os.dup2(existing, desired) try: self._remove_nonblock_flag(desired) except OSError: # Ignore EBADF, it may not actually be # open yet. # Tested beginning in 3.7.0b3 test_subprocess.py pass _dup2(p2cread, 0) _dup2(c2pwrite, 1) _dup2(errwrite, 2) # Close pipe fds. Make sure we don't close the # same fd more than once, or standard fds. if not True: closed = set([None]) for fd in (p2cread, c2pwrite, errwrite): if fd not in closed and fd > 2: os.close(fd) closed.add(fd) # Python 3 (with a working set_inheritable): # We no longer manually close p2cread, # c2pwrite, and errwrite here as # _close_open_fds takes care when it is # not already non-inheritable. if cwd is not None: try: os.chdir(cwd) except OSError as e: e._failed_chdir = True raise # Python 3.9 if umask >= 0: os.umask(umask) # XXX: CPython does _Py_RestoreSignals here. # Then setsid() based on ??? try: if gids: os.setgroups(gids) if gid: os.setregid(gid, gid) if uid: os.setreuid(uid, uid) if process_group is not None: os.setpgid(0, process_group) except OSError as e: e._failed_chuser = True raise if preexec_fn: preexec_fn() # Close all other fds, if asked for. This must be done # after preexec_fn runs. if close_fds: fds_to_keep = set(pass_fds) fds_to_keep.add(errpipe_write) self._close_fds(fds_to_keep, errpipe_write) if restore_signals: # restore the documented signals back to sig_dfl; # not all will be defined on every platform for sig in 'SIGPIPE', 'SIGXFZ', 'SIGXFSZ': sig = getattr(signal, sig, None) if sig is not None: signal.signal(sig, signal.SIG_DFL) if start_new_session: os.setsid() try: if env is None: os.execvp(executable, args) else: # Python 3.6 started testing for # bytes values in the env; it also # started encoding strs using # fsencode and using a lower-level # API that takes a list of keys # and values. We don't have access # to that API, so we go the reverse direction. env = {os.fsdecode(k) if isinstance(k, bytes) else k: os.fsdecode(v) if isinstance(v, bytes) else v for k, v in env.items()} os.execvpe(executable, args, env) except OSError as e: e._failed_exec = True raise except: exc_type, exc_value, tb = sys.exc_info() # Save the traceback and attach it to the exception object exc_lines = traceback.format_exception(exc_type, exc_value, tb) exc_value.child_traceback = ''.join(exc_lines) os.write(errpipe_write, pickle.dumps(exc_value)) finally: # Make sure that the process exits no matter what. # The return code does not matter much as it won't be # reported to the application os._exit(1) # Parent self._child_created = True if gc_was_enabled: gc.enable() finally: # be sure the FD is closed no matter what os.close(errpipe_write) # self._devnull is not always defined. devnull_fd = getattr(self, '_devnull', None) if p2cread != -1 and p2cwrite != -1 and p2cread != devnull_fd: os.close(p2cread) if c2pwrite != -1 and c2pread != -1 and c2pwrite != devnull_fd: os.close(c2pwrite) if errwrite != -1 and errread != -1 and errwrite != devnull_fd: os.close(errwrite) if devnull_fd is not None: os.close(devnull_fd) # Prevent a double close of these fds from __init__ on error. self._closed_child_pipe_fds = True # Wait for exec to fail or succeed; possibly raising exception errpipe_read = FileObject(errpipe_read, 'rb') data = errpipe_read.read() finally: try: if hasattr(errpipe_read, 'close'): errpipe_read.close() else: os.close(errpipe_read) except OSError: # Especially on PyPy, we sometimes see the above # `os.close(errpipe_read)` raise an OSError. # It's not entirely clear why, but it happens in # InterprocessSignalTests.test_main sometimes, which must mean # we have some sort of race condition. pass finally: errpipe_read = -1 if data != b"": self.wait() child_exception = pickle.loads(data) for fd in (p2cwrite, c2pread, errread): if fd is not None and fd != -1: os.close(fd) if isinstance(child_exception, OSError): child_exception.filename = executable if hasattr(child_exception, '_failed_chdir'): child_exception.filename = cwd if getattr(child_exception, '_failed_chuser', False): child_exception.filename = None > raise child_exception E OSError: [Errno 8] Exec format error: 'locust' /usr/lib/python3/dist-packages/gevent/subprocess.py:1838: OSError __________________ DistributedIntegrationTests.test_processes __________________ self = @unittest.skipIf(os.name == "nt", reason="--processes doesnt work on windows") def test_processes(self): with mock_locustfile() as mocked: command = f"locust -f {mocked.file_path} --processes 4 --headless --run-time 1 --exit-code-on-error 0" proc = subprocess.Popen( command, shell=True, stdout=PIPE, stderr=PIPE, text=True, ) try: _, stderr = proc.communicate(timeout=9) except Exception: proc.kill() assert False, f"locust process never finished: {command}" self.assertNotIn("Traceback", stderr) > self.assertIn("(index 3) reported as ready", stderr) E AssertionError: '(index 3) reported as ready' not found in '/build/reproducible-path/locust-2.24.0/debian/locust: line 2: from: command not found\n/build/reproducible-path/locust-2.24.0/debian/locust: line 5: syntax error: unexpected end of file\n' locust/test/test_main.py:1993: AssertionError ____________ DistributedIntegrationTests.test_processes_autodetect _____________ self = @unittest.skipIf(os.name == "nt", reason="--processes doesnt work on windows") def test_processes_autodetect(self): with mock_locustfile() as mocked: command = f"locust -f {mocked.file_path} --processes -1 --headless --run-time 1 --exit-code-on-error 0" proc = subprocess.Popen( command, shell=True, stdout=PIPE, stderr=PIPE, text=True, ) try: _, stderr = proc.communicate(timeout=9) except Exception: proc.kill() assert False, f"locust process never finished: {command}" self.assertNotIn("Traceback", stderr) > self.assertIn("(index 0) reported as ready", stderr) E AssertionError: '(index 0) reported as ready' not found in '/build/reproducible-path/locust-2.24.0/debian/locust: line 2: from: command not found\n/build/reproducible-path/locust-2.24.0/debian/locust: line 5: syntax error: unexpected end of file\n' locust/test/test_main.py:2013: AssertionError ______________ DistributedIntegrationTests.test_processes_ctrl_c _______________ self = @unittest.skipIf(os.name == "nt", reason="--processes doesnt work on windows") def test_processes_ctrl_c(self): with mock_locustfile() as mocked: > proc = psutil.Popen( # use psutil.Popen instead of subprocess.Popen to use extra features [ "locust", "-f", mocked.file_path, "--processes", "4", "--headless", "-L", "DEBUG", ], stdout=PIPE, stderr=PIPE, text=True, ) locust/test/test_main.py:2064: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3/dist-packages/psutil/__init__.py:1378: in __init__ self.__subproc = subprocess.Popen(*args, **kwargs) /usr/lib/python3/dist-packages/gevent/subprocess.py:808: in __init__ self._execute_child(args, executable, preexec_fn, close_fds, _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = args = ['locust', '-f', '/build/reproducible-path/locust-2.24.0/locust/test/mock_locustfile_1715256388_7593384_31897.py', '--processes', '4', '--headless', ...] executable = 'locust', preexec_fn = None, close_fds = True, pass_fds = () cwd = None, env = None, universal_newlines = None, startupinfo = None creationflags = 0, shell = False, p2cread = -1, p2cwrite = -1, c2pread = 11 c2pwrite = 81, errread = 82, errwrite = 83, restore_signals = True, gid = None gids = None, uid = None, umask = -1, start_new_session = False process_group = None def _execute_child(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, universal_newlines, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, restore_signals, gid, gids, uid, umask, start_new_session, process_group): """Execute program (POSIX version)""" if isinstance(args, (str, bytes)): args = [args] elif isinstance(args, PathLike): if shell: raise TypeError('path-like args is not allowed when ' 'shell is true') args = [fsencode(args)] # os.PathLike -> [str] else: args = list(args) if shell: # On Android the default shell is at '/system/bin/sh'. unix_shell = ( '/system/bin/sh' if hasattr(sys, 'getandroidapilevel') else '/bin/sh' ) args = [unix_shell, "-c"] + args if executable: args[0] = executable if executable is None: executable = args[0] self._loop.install_sigchld() # For transferring possible exec failure from child to parent # The first char specifies the exception type: 0 means # OSError, 1 means some other error. errpipe_read, errpipe_write = self.pipe_cloexec() # errpipe_write must not be in the standard io 0, 1, or 2 fd range. low_fds_to_close = [] while errpipe_write < 3: low_fds_to_close.append(errpipe_write) errpipe_write = os.dup(errpipe_write) for low_fd in low_fds_to_close: os.close(low_fd) try: try: gc_was_enabled = gc.isenabled() # Disable gc to avoid bug where gc -> file_dealloc -> # write to stderr -> hang. http://bugs.python.org/issue1336 gc.disable() try: self.pid = fork_and_watch(self._on_child, self._loop, True, fork) except: if gc_was_enabled: gc.enable() raise if self.pid == 0: # Child # In various places on the child side of things, we catch OSError # and add attributes to it that detail where in the process we failed; # like all exceptions until we have exec'd, this exception is pickled # and sent to the parent to raise in the calling process. # The parent uses this to decide how to treat that exception, # adjusting certain information about it as needed. # # Python 3.11.8 --- yes, a minor patch release --- stopped # letting the 'filename' parameter get set in the resulting # exception for many cases. We're not quite interpreting this # the same way the stdlib is, I'm sure, but this makes the stdlib # tests pass. # XXX: Technically we're doing a lot of stuff here that # may not be safe to do before a exec(), depending on the OS. # CPython 3 goes to great lengths to precompute a lot # of this info before the fork and pass it all to C functions that # try hard not to call things like malloc(). (Of course, # CPython 2 pretty much did what we're doing.) try: # Close parent's pipe ends if p2cwrite != -1: os.close(p2cwrite) if c2pread != -1: os.close(c2pread) if errread != -1: os.close(errread) os.close(errpipe_read) # When duping fds, if there arises a situation # where one of the fds is either 0, 1 or 2, it # is possible that it is overwritten (#12607). if c2pwrite == 0: c2pwrite = os.dup(c2pwrite) _set_inheritable(c2pwrite, False) while errwrite in (0, 1): errwrite = os.dup(errwrite) _set_inheritable(errwrite, False) # Dup fds for child def _dup2(existing, desired): # dup2() removes the CLOEXEC flag but # we must do it ourselves if dup2() # would be a no-op (issue #10806). if existing == desired: self._set_cloexec_flag(existing, False) elif existing != -1: os.dup2(existing, desired) try: self._remove_nonblock_flag(desired) except OSError: # Ignore EBADF, it may not actually be # open yet. # Tested beginning in 3.7.0b3 test_subprocess.py pass _dup2(p2cread, 0) _dup2(c2pwrite, 1) _dup2(errwrite, 2) # Close pipe fds. Make sure we don't close the # same fd more than once, or standard fds. if not True: closed = set([None]) for fd in (p2cread, c2pwrite, errwrite): if fd not in closed and fd > 2: os.close(fd) closed.add(fd) # Python 3 (with a working set_inheritable): # We no longer manually close p2cread, # c2pwrite, and errwrite here as # _close_open_fds takes care when it is # not already non-inheritable. if cwd is not None: try: os.chdir(cwd) except OSError as e: e._failed_chdir = True raise # Python 3.9 if umask >= 0: os.umask(umask) # XXX: CPython does _Py_RestoreSignals here. # Then setsid() based on ??? try: if gids: os.setgroups(gids) if gid: os.setregid(gid, gid) if uid: os.setreuid(uid, uid) if process_group is not None: os.setpgid(0, process_group) except OSError as e: e._failed_chuser = True raise if preexec_fn: preexec_fn() # Close all other fds, if asked for. This must be done # after preexec_fn runs. if close_fds: fds_to_keep = set(pass_fds) fds_to_keep.add(errpipe_write) self._close_fds(fds_to_keep, errpipe_write) if restore_signals: # restore the documented signals back to sig_dfl; # not all will be defined on every platform for sig in 'SIGPIPE', 'SIGXFZ', 'SIGXFSZ': sig = getattr(signal, sig, None) if sig is not None: signal.signal(sig, signal.SIG_DFL) if start_new_session: os.setsid() try: if env is None: os.execvp(executable, args) else: # Python 3.6 started testing for # bytes values in the env; it also # started encoding strs using # fsencode and using a lower-level # API that takes a list of keys # and values. We don't have access # to that API, so we go the reverse direction. env = {os.fsdecode(k) if isinstance(k, bytes) else k: os.fsdecode(v) if isinstance(v, bytes) else v for k, v in env.items()} os.execvpe(executable, args, env) except OSError as e: e._failed_exec = True raise except: exc_type, exc_value, tb = sys.exc_info() # Save the traceback and attach it to the exception object exc_lines = traceback.format_exception(exc_type, exc_value, tb) exc_value.child_traceback = ''.join(exc_lines) os.write(errpipe_write, pickle.dumps(exc_value)) finally: # Make sure that the process exits no matter what. # The return code does not matter much as it won't be # reported to the application os._exit(1) # Parent self._child_created = True if gc_was_enabled: gc.enable() finally: # be sure the FD is closed no matter what os.close(errpipe_write) # self._devnull is not always defined. devnull_fd = getattr(self, '_devnull', None) if p2cread != -1 and p2cwrite != -1 and p2cread != devnull_fd: os.close(p2cread) if c2pwrite != -1 and c2pread != -1 and c2pwrite != devnull_fd: os.close(c2pwrite) if errwrite != -1 and errread != -1 and errwrite != devnull_fd: os.close(errwrite) if devnull_fd is not None: os.close(devnull_fd) # Prevent a double close of these fds from __init__ on error. self._closed_child_pipe_fds = True # Wait for exec to fail or succeed; possibly raising exception errpipe_read = FileObject(errpipe_read, 'rb') data = errpipe_read.read() finally: try: if hasattr(errpipe_read, 'close'): errpipe_read.close() else: os.close(errpipe_read) except OSError: # Especially on PyPy, we sometimes see the above # `os.close(errpipe_read)` raise an OSError. # It's not entirely clear why, but it happens in # InterprocessSignalTests.test_main sometimes, which must mean # we have some sort of race condition. pass finally: errpipe_read = -1 if data != b"": self.wait() child_exception = pickle.loads(data) for fd in (p2cwrite, c2pread, errread): if fd is not None and fd != -1: os.close(fd) if isinstance(child_exception, OSError): child_exception.filename = executable if hasattr(child_exception, '_failed_chdir'): child_exception.filename = cwd if getattr(child_exception, '_failed_chuser', False): child_exception.filename = None > raise child_exception E OSError: [Errno 8] Exec format error: 'locust' /usr/lib/python3/dist-packages/gevent/subprocess.py:1838: OSError __ DistributedIntegrationTests.test_processes_error_doesnt_blow_up_completely __ self = @unittest.skipIf(os.name == "nt", reason="--processes doesnt work on windows") def test_processes_error_doesnt_blow_up_completely(self): with mock_locustfile() as mocked: > proc = subprocess.Popen( [ "locust", "-f", mocked.file_path, "--processes", "4", "-L", "DEBUG", "UserThatDoesntExist", ], stdout=PIPE, stderr=PIPE, text=True, ) locust/test/test_main.py:2162: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3/dist-packages/gevent/subprocess.py:808: in __init__ self._execute_child(args, executable, preexec_fn, close_fds, _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = args = ['locust', '-f', '/build/reproducible-path/locust-2.24.0/locust/test/mock_locustfile_1715256389_0042963_6490.py', '--processes', '4', '-L', ...] executable = 'locust', preexec_fn = None, close_fds = True, pass_fds = () cwd = None, env = None, universal_newlines = None, startupinfo = None creationflags = 0, shell = False, p2cread = -1, p2cwrite = -1, c2pread = 11 c2pwrite = 81, errread = 82, errwrite = 83, restore_signals = True, gid = None gids = None, uid = None, umask = -1, start_new_session = False process_group = None def _execute_child(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, universal_newlines, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, restore_signals, gid, gids, uid, umask, start_new_session, process_group): """Execute program (POSIX version)""" if isinstance(args, (str, bytes)): args = [args] elif isinstance(args, PathLike): if shell: raise TypeError('path-like args is not allowed when ' 'shell is true') args = [fsencode(args)] # os.PathLike -> [str] else: args = list(args) if shell: # On Android the default shell is at '/system/bin/sh'. unix_shell = ( '/system/bin/sh' if hasattr(sys, 'getandroidapilevel') else '/bin/sh' ) args = [unix_shell, "-c"] + args if executable: args[0] = executable if executable is None: executable = args[0] self._loop.install_sigchld() # For transferring possible exec failure from child to parent # The first char specifies the exception type: 0 means # OSError, 1 means some other error. errpipe_read, errpipe_write = self.pipe_cloexec() # errpipe_write must not be in the standard io 0, 1, or 2 fd range. low_fds_to_close = [] while errpipe_write < 3: low_fds_to_close.append(errpipe_write) errpipe_write = os.dup(errpipe_write) for low_fd in low_fds_to_close: os.close(low_fd) try: try: gc_was_enabled = gc.isenabled() # Disable gc to avoid bug where gc -> file_dealloc -> # write to stderr -> hang. http://bugs.python.org/issue1336 gc.disable() try: self.pid = fork_and_watch(self._on_child, self._loop, True, fork) except: if gc_was_enabled: gc.enable() raise if self.pid == 0: # Child # In various places on the child side of things, we catch OSError # and add attributes to it that detail where in the process we failed; # like all exceptions until we have exec'd, this exception is pickled # and sent to the parent to raise in the calling process. # The parent uses this to decide how to treat that exception, # adjusting certain information about it as needed. # # Python 3.11.8 --- yes, a minor patch release --- stopped # letting the 'filename' parameter get set in the resulting # exception for many cases. We're not quite interpreting this # the same way the stdlib is, I'm sure, but this makes the stdlib # tests pass. # XXX: Technically we're doing a lot of stuff here that # may not be safe to do before a exec(), depending on the OS. # CPython 3 goes to great lengths to precompute a lot # of this info before the fork and pass it all to C functions that # try hard not to call things like malloc(). (Of course, # CPython 2 pretty much did what we're doing.) try: # Close parent's pipe ends if p2cwrite != -1: os.close(p2cwrite) if c2pread != -1: os.close(c2pread) if errread != -1: os.close(errread) os.close(errpipe_read) # When duping fds, if there arises a situation # where one of the fds is either 0, 1 or 2, it # is possible that it is overwritten (#12607). if c2pwrite == 0: c2pwrite = os.dup(c2pwrite) _set_inheritable(c2pwrite, False) while errwrite in (0, 1): errwrite = os.dup(errwrite) _set_inheritable(errwrite, False) # Dup fds for child def _dup2(existing, desired): # dup2() removes the CLOEXEC flag but # we must do it ourselves if dup2() # would be a no-op (issue #10806). if existing == desired: self._set_cloexec_flag(existing, False) elif existing != -1: os.dup2(existing, desired) try: self._remove_nonblock_flag(desired) except OSError: # Ignore EBADF, it may not actually be # open yet. # Tested beginning in 3.7.0b3 test_subprocess.py pass _dup2(p2cread, 0) _dup2(c2pwrite, 1) _dup2(errwrite, 2) # Close pipe fds. Make sure we don't close the # same fd more than once, or standard fds. if not True: closed = set([None]) for fd in (p2cread, c2pwrite, errwrite): if fd not in closed and fd > 2: os.close(fd) closed.add(fd) # Python 3 (with a working set_inheritable): # We no longer manually close p2cread, # c2pwrite, and errwrite here as # _close_open_fds takes care when it is # not already non-inheritable. if cwd is not None: try: os.chdir(cwd) except OSError as e: e._failed_chdir = True raise # Python 3.9 if umask >= 0: os.umask(umask) # XXX: CPython does _Py_RestoreSignals here. # Then setsid() based on ??? try: if gids: os.setgroups(gids) if gid: os.setregid(gid, gid) if uid: os.setreuid(uid, uid) if process_group is not None: os.setpgid(0, process_group) except OSError as e: e._failed_chuser = True raise if preexec_fn: preexec_fn() # Close all other fds, if asked for. This must be done # after preexec_fn runs. if close_fds: fds_to_keep = set(pass_fds) fds_to_keep.add(errpipe_write) self._close_fds(fds_to_keep, errpipe_write) if restore_signals: # restore the documented signals back to sig_dfl; # not all will be defined on every platform for sig in 'SIGPIPE', 'SIGXFZ', 'SIGXFSZ': sig = getattr(signal, sig, None) if sig is not None: signal.signal(sig, signal.SIG_DFL) if start_new_session: os.setsid() try: if env is None: os.execvp(executable, args) else: # Python 3.6 started testing for # bytes values in the env; it also # started encoding strs using # fsencode and using a lower-level # API that takes a list of keys # and values. We don't have access # to that API, so we go the reverse direction. env = {os.fsdecode(k) if isinstance(k, bytes) else k: os.fsdecode(v) if isinstance(v, bytes) else v for k, v in env.items()} os.execvpe(executable, args, env) except OSError as e: e._failed_exec = True raise except: exc_type, exc_value, tb = sys.exc_info() # Save the traceback and attach it to the exception object exc_lines = traceback.format_exception(exc_type, exc_value, tb) exc_value.child_traceback = ''.join(exc_lines) os.write(errpipe_write, pickle.dumps(exc_value)) finally: # Make sure that the process exits no matter what. # The return code does not matter much as it won't be # reported to the application os._exit(1) # Parent self._child_created = True if gc_was_enabled: gc.enable() finally: # be sure the FD is closed no matter what os.close(errpipe_write) # self._devnull is not always defined. devnull_fd = getattr(self, '_devnull', None) if p2cread != -1 and p2cwrite != -1 and p2cread != devnull_fd: os.close(p2cread) if c2pwrite != -1 and c2pread != -1 and c2pwrite != devnull_fd: os.close(c2pwrite) if errwrite != -1 and errread != -1 and errwrite != devnull_fd: os.close(errwrite) if devnull_fd is not None: os.close(devnull_fd) # Prevent a double close of these fds from __init__ on error. self._closed_child_pipe_fds = True # Wait for exec to fail or succeed; possibly raising exception errpipe_read = FileObject(errpipe_read, 'rb') data = errpipe_read.read() finally: try: if hasattr(errpipe_read, 'close'): errpipe_read.close() else: os.close(errpipe_read) except OSError: # Especially on PyPy, we sometimes see the above # `os.close(errpipe_read)` raise an OSError. # It's not entirely clear why, but it happens in # InterprocessSignalTests.test_main sometimes, which must mean # we have some sort of race condition. pass finally: errpipe_read = -1 if data != b"": self.wait() child_exception = pickle.loads(data) for fd in (p2cwrite, c2pread, errread): if fd is not None and fd != -1: os.close(fd) if isinstance(child_exception, OSError): child_exception.filename = executable if hasattr(child_exception, '_failed_chdir'): child_exception.filename = cwd if getattr(child_exception, '_failed_chuser', False): child_exception.filename = None > raise child_exception E OSError: [Errno 8] Exec format error: 'locust' /usr/lib/python3/dist-packages/gevent/subprocess.py:1838: OSError __________ DistributedIntegrationTests.test_processes_separate_worker __________ self = @unittest.skipIf(os.name == "nt", reason="--processes doesnt work on windows") def test_processes_separate_worker(self): with mock_locustfile() as mocked: master_proc = subprocess.Popen( f"locust -f {mocked.file_path} --master --headless --run-time 1 --exit-code-on-error 0 --expect-workers-max-wait 2", shell=True, stdout=PIPE, stderr=PIPE, text=True, ) worker_parent_proc = subprocess.Popen( f"locust -f {mocked.file_path} --processes 4 --worker", shell=True, stdout=PIPE, stderr=PIPE, text=True, ) try: _, worker_stderr = worker_parent_proc.communicate(timeout=9) except Exception: master_proc.kill() worker_parent_proc.kill() _, worker_stderr = worker_parent_proc.communicate() _, master_stderr = master_proc.communicate() assert False, f"worker never finished: {worker_stderr}" try: _, master_stderr = master_proc.communicate(timeout=9) except Exception: master_proc.kill() worker_parent_proc.kill() _, worker_stderr = worker_parent_proc.communicate() _, master_stderr = master_proc.communicate() assert False, f"master never finished: {master_stderr}" _, worker_stderr = worker_parent_proc.communicate() _, master_stderr = master_proc.communicate() self.assertNotIn("Traceback", worker_stderr) self.assertNotIn("Traceback", master_stderr) self.assertNotIn("Gave up waiting for workers to connect", master_stderr) > self.assertIn("(index 3) reported as ready", master_stderr) E AssertionError: '(index 3) reported as ready' not found in '/build/reproducible-path/locust-2.24.0/debian/locust: line 2: from: command not found\n/build/reproducible-path/locust-2.24.0/debian/locust: line 5: syntax error: unexpected end of file\n' locust/test/test_main.py:2058: AssertionError ______ DistributedIntegrationTests.test_processes_workers_quit_unexpected ______ self = @unittest.skipIf(os.name == "nt", reason="--processes doesnt work on windows") @unittest.skipIf(sys.platform == "darwin", reason="Flaky on macOS :-/") def test_processes_workers_quit_unexpected(self): content = """ from locust import runners, events, User, task import sys runners.HEARTBEAT_INTERVAL = 0.1 @events.test_start.add_listener def on_test_start(environment, **_kwargs): if isinstance(environment.runner, runners.WorkerRunner): sys.exit(42) class AnyUser(User): @task def mytask(self): pass """ with mock_locustfile(content=content) as mocked: > worker_proc = subprocess.Popen( ["locust", "-f", mocked.file_path, "--processes", "2", "--worker"], stdout=PIPE, stderr=PIPE, text=True, ) locust/test/test_main.py:2202: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3/dist-packages/gevent/subprocess.py:808: in __init__ self._execute_child(args, executable, preexec_fn, close_fds, _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = args = ['locust', '-f', '/build/reproducible-path/locust-2.24.0/locust/test/mock_locustfile_1715256389_4273727_91214.py', '--processes', '2', '--worker'] executable = 'locust', preexec_fn = None, close_fds = True, pass_fds = () cwd = None, env = None, universal_newlines = None, startupinfo = None creationflags = 0, shell = False, p2cread = -1, p2cwrite = -1, c2pread = 11 c2pwrite = 81, errread = 82, errwrite = 83, restore_signals = True, gid = None gids = None, uid = None, umask = -1, start_new_session = False process_group = None def _execute_child(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, universal_newlines, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, restore_signals, gid, gids, uid, umask, start_new_session, process_group): """Execute program (POSIX version)""" if isinstance(args, (str, bytes)): args = [args] elif isinstance(args, PathLike): if shell: raise TypeError('path-like args is not allowed when ' 'shell is true') args = [fsencode(args)] # os.PathLike -> [str] else: args = list(args) if shell: # On Android the default shell is at '/system/bin/sh'. unix_shell = ( '/system/bin/sh' if hasattr(sys, 'getandroidapilevel') else '/bin/sh' ) args = [unix_shell, "-c"] + args if executable: args[0] = executable if executable is None: executable = args[0] self._loop.install_sigchld() # For transferring possible exec failure from child to parent # The first char specifies the exception type: 0 means # OSError, 1 means some other error. errpipe_read, errpipe_write = self.pipe_cloexec() # errpipe_write must not be in the standard io 0, 1, or 2 fd range. low_fds_to_close = [] while errpipe_write < 3: low_fds_to_close.append(errpipe_write) errpipe_write = os.dup(errpipe_write) for low_fd in low_fds_to_close: os.close(low_fd) try: try: gc_was_enabled = gc.isenabled() # Disable gc to avoid bug where gc -> file_dealloc -> # write to stderr -> hang. http://bugs.python.org/issue1336 gc.disable() try: self.pid = fork_and_watch(self._on_child, self._loop, True, fork) except: if gc_was_enabled: gc.enable() raise if self.pid == 0: # Child # In various places on the child side of things, we catch OSError # and add attributes to it that detail where in the process we failed; # like all exceptions until we have exec'd, this exception is pickled # and sent to the parent to raise in the calling process. # The parent uses this to decide how to treat that exception, # adjusting certain information about it as needed. # # Python 3.11.8 --- yes, a minor patch release --- stopped # letting the 'filename' parameter get set in the resulting # exception for many cases. We're not quite interpreting this # the same way the stdlib is, I'm sure, but this makes the stdlib # tests pass. # XXX: Technically we're doing a lot of stuff here that # may not be safe to do before a exec(), depending on the OS. # CPython 3 goes to great lengths to precompute a lot # of this info before the fork and pass it all to C functions that # try hard not to call things like malloc(). (Of course, # CPython 2 pretty much did what we're doing.) try: # Close parent's pipe ends if p2cwrite != -1: os.close(p2cwrite) if c2pread != -1: os.close(c2pread) if errread != -1: os.close(errread) os.close(errpipe_read) # When duping fds, if there arises a situation # where one of the fds is either 0, 1 or 2, it # is possible that it is overwritten (#12607). if c2pwrite == 0: c2pwrite = os.dup(c2pwrite) _set_inheritable(c2pwrite, False) while errwrite in (0, 1): errwrite = os.dup(errwrite) _set_inheritable(errwrite, False) # Dup fds for child def _dup2(existing, desired): # dup2() removes the CLOEXEC flag but # we must do it ourselves if dup2() # would be a no-op (issue #10806). if existing == desired: self._set_cloexec_flag(existing, False) elif existing != -1: os.dup2(existing, desired) try: self._remove_nonblock_flag(desired) except OSError: # Ignore EBADF, it may not actually be # open yet. # Tested beginning in 3.7.0b3 test_subprocess.py pass _dup2(p2cread, 0) _dup2(c2pwrite, 1) _dup2(errwrite, 2) # Close pipe fds. Make sure we don't close the # same fd more than once, or standard fds. if not True: closed = set([None]) for fd in (p2cread, c2pwrite, errwrite): if fd not in closed and fd > 2: os.close(fd) closed.add(fd) # Python 3 (with a working set_inheritable): # We no longer manually close p2cread, # c2pwrite, and errwrite here as # _close_open_fds takes care when it is # not already non-inheritable. if cwd is not None: try: os.chdir(cwd) except OSError as e: e._failed_chdir = True raise # Python 3.9 if umask >= 0: os.umask(umask) # XXX: CPython does _Py_RestoreSignals here. # Then setsid() based on ??? try: if gids: os.setgroups(gids) if gid: os.setregid(gid, gid) if uid: os.setreuid(uid, uid) if process_group is not None: os.setpgid(0, process_group) except OSError as e: e._failed_chuser = True raise if preexec_fn: preexec_fn() # Close all other fds, if asked for. This must be done # after preexec_fn runs. if close_fds: fds_to_keep = set(pass_fds) fds_to_keep.add(errpipe_write) self._close_fds(fds_to_keep, errpipe_write) if restore_signals: # restore the documented signals back to sig_dfl; # not all will be defined on every platform for sig in 'SIGPIPE', 'SIGXFZ', 'SIGXFSZ': sig = getattr(signal, sig, None) if sig is not None: signal.signal(sig, signal.SIG_DFL) if start_new_session: os.setsid() try: if env is None: os.execvp(executable, args) else: # Python 3.6 started testing for # bytes values in the env; it also # started encoding strs using # fsencode and using a lower-level # API that takes a list of keys # and values. We don't have access # to that API, so we go the reverse direction. env = {os.fsdecode(k) if isinstance(k, bytes) else k: os.fsdecode(v) if isinstance(v, bytes) else v for k, v in env.items()} os.execvpe(executable, args, env) except OSError as e: e._failed_exec = True raise except: exc_type, exc_value, tb = sys.exc_info() # Save the traceback and attach it to the exception object exc_lines = traceback.format_exception(exc_type, exc_value, tb) exc_value.child_traceback = ''.join(exc_lines) os.write(errpipe_write, pickle.dumps(exc_value)) finally: # Make sure that the process exits no matter what. # The return code does not matter much as it won't be # reported to the application os._exit(1) # Parent self._child_created = True if gc_was_enabled: gc.enable() finally: # be sure the FD is closed no matter what os.close(errpipe_write) # self._devnull is not always defined. devnull_fd = getattr(self, '_devnull', None) if p2cread != -1 and p2cwrite != -1 and p2cread != devnull_fd: os.close(p2cread) if c2pwrite != -1 and c2pread != -1 and c2pwrite != devnull_fd: os.close(c2pwrite) if errwrite != -1 and errread != -1 and errwrite != devnull_fd: os.close(errwrite) if devnull_fd is not None: os.close(devnull_fd) # Prevent a double close of these fds from __init__ on error. self._closed_child_pipe_fds = True # Wait for exec to fail or succeed; possibly raising exception errpipe_read = FileObject(errpipe_read, 'rb') data = errpipe_read.read() finally: try: if hasattr(errpipe_read, 'close'): errpipe_read.close() else: os.close(errpipe_read) except OSError: # Especially on PyPy, we sometimes see the above # `os.close(errpipe_read)` raise an OSError. # It's not entirely clear why, but it happens in # InterprocessSignalTests.test_main sometimes, which must mean # we have some sort of race condition. pass finally: errpipe_read = -1 if data != b"": self.wait() child_exception = pickle.loads(data) for fd in (p2cwrite, c2pread, errread): if fd is not None and fd != -1: os.close(fd) if isinstance(child_exception, OSError): child_exception.filename = executable if hasattr(child_exception, '_failed_chdir'): child_exception.filename = cwd if getattr(child_exception, '_failed_chuser', False): child_exception.filename = None > raise child_exception E OSError: [Errno 8] Exec format error: 'locust' /usr/lib/python3/dist-packages/gevent/subprocess.py:1838: OSError _______________ DistributedIntegrationTests.test_worker_indexes ________________ self = def test_worker_indexes(self): content = """ from locust import HttpUser, task, between class AnyUser(HttpUser): host = "http://127.0.0.1:8089" wait_time = between(0, 0.1) @task def my_task(self): print("worker index:", self.environment.runner.worker_index) """ with mock_locustfile(content=content) as mocked: > master = subprocess.Popen( [ "locust", "-f", mocked.file_path, "--headless", "--master", "--expect-workers", "2", "-t", "5", "-u", "2", "-L", "DEBUG", ], stdout=PIPE, stderr=PIPE, text=True, ) locust/test/test_main.py:1900: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3/dist-packages/gevent/subprocess.py:808: in __init__ self._execute_child(args, executable, preexec_fn, close_fds, _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = args = ['locust', '-f', '/build/reproducible-path/locust-2.24.0/locust/test/mock_locustfile_1715256389_5419211_11576.py', '--headless', '--master', '--expect-workers', ...] executable = 'locust', preexec_fn = None, close_fds = True, pass_fds = () cwd = None, env = None, universal_newlines = None, startupinfo = None creationflags = 0, shell = False, p2cread = -1, p2cwrite = -1, c2pread = 11 c2pwrite = 81, errread = 82, errwrite = 83, restore_signals = True, gid = None gids = None, uid = None, umask = -1, start_new_session = False process_group = None def _execute_child(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, universal_newlines, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, restore_signals, gid, gids, uid, umask, start_new_session, process_group): """Execute program (POSIX version)""" if isinstance(args, (str, bytes)): args = [args] elif isinstance(args, PathLike): if shell: raise TypeError('path-like args is not allowed when ' 'shell is true') args = [fsencode(args)] # os.PathLike -> [str] else: args = list(args) if shell: # On Android the default shell is at '/system/bin/sh'. unix_shell = ( '/system/bin/sh' if hasattr(sys, 'getandroidapilevel') else '/bin/sh' ) args = [unix_shell, "-c"] + args if executable: args[0] = executable if executable is None: executable = args[0] self._loop.install_sigchld() # For transferring possible exec failure from child to parent # The first char specifies the exception type: 0 means # OSError, 1 means some other error. errpipe_read, errpipe_write = self.pipe_cloexec() # errpipe_write must not be in the standard io 0, 1, or 2 fd range. low_fds_to_close = [] while errpipe_write < 3: low_fds_to_close.append(errpipe_write) errpipe_write = os.dup(errpipe_write) for low_fd in low_fds_to_close: os.close(low_fd) try: try: gc_was_enabled = gc.isenabled() # Disable gc to avoid bug where gc -> file_dealloc -> # write to stderr -> hang. http://bugs.python.org/issue1336 gc.disable() try: self.pid = fork_and_watch(self._on_child, self._loop, True, fork) except: if gc_was_enabled: gc.enable() raise if self.pid == 0: # Child # In various places on the child side of things, we catch OSError # and add attributes to it that detail where in the process we failed; # like all exceptions until we have exec'd, this exception is pickled # and sent to the parent to raise in the calling process. # The parent uses this to decide how to treat that exception, # adjusting certain information about it as needed. # # Python 3.11.8 --- yes, a minor patch release --- stopped # letting the 'filename' parameter get set in the resulting # exception for many cases. We're not quite interpreting this # the same way the stdlib is, I'm sure, but this makes the stdlib # tests pass. # XXX: Technically we're doing a lot of stuff here that # may not be safe to do before a exec(), depending on the OS. # CPython 3 goes to great lengths to precompute a lot # of this info before the fork and pass it all to C functions that # try hard not to call things like malloc(). (Of course, # CPython 2 pretty much did what we're doing.) try: # Close parent's pipe ends if p2cwrite != -1: os.close(p2cwrite) if c2pread != -1: os.close(c2pread) if errread != -1: os.close(errread) os.close(errpipe_read) # When duping fds, if there arises a situation # where one of the fds is either 0, 1 or 2, it # is possible that it is overwritten (#12607). if c2pwrite == 0: c2pwrite = os.dup(c2pwrite) _set_inheritable(c2pwrite, False) while errwrite in (0, 1): errwrite = os.dup(errwrite) _set_inheritable(errwrite, False) # Dup fds for child def _dup2(existing, desired): # dup2() removes the CLOEXEC flag but # we must do it ourselves if dup2() # would be a no-op (issue #10806). if existing == desired: self._set_cloexec_flag(existing, False) elif existing != -1: os.dup2(existing, desired) try: self._remove_nonblock_flag(desired) except OSError: # Ignore EBADF, it may not actually be # open yet. # Tested beginning in 3.7.0b3 test_subprocess.py pass _dup2(p2cread, 0) _dup2(c2pwrite, 1) _dup2(errwrite, 2) # Close pipe fds. Make sure we don't close the # same fd more than once, or standard fds. if not True: closed = set([None]) for fd in (p2cread, c2pwrite, errwrite): if fd not in closed and fd > 2: os.close(fd) closed.add(fd) # Python 3 (with a working set_inheritable): # We no longer manually close p2cread, # c2pwrite, and errwrite here as # _close_open_fds takes care when it is # not already non-inheritable. if cwd is not None: try: os.chdir(cwd) except OSError as e: e._failed_chdir = True raise # Python 3.9 if umask >= 0: os.umask(umask) # XXX: CPython does _Py_RestoreSignals here. # Then setsid() based on ??? try: if gids: os.setgroups(gids) if gid: os.setregid(gid, gid) if uid: os.setreuid(uid, uid) if process_group is not None: os.setpgid(0, process_group) except OSError as e: e._failed_chuser = True raise if preexec_fn: preexec_fn() # Close all other fds, if asked for. This must be done # after preexec_fn runs. if close_fds: fds_to_keep = set(pass_fds) fds_to_keep.add(errpipe_write) self._close_fds(fds_to_keep, errpipe_write) if restore_signals: # restore the documented signals back to sig_dfl; # not all will be defined on every platform for sig in 'SIGPIPE', 'SIGXFZ', 'SIGXFSZ': sig = getattr(signal, sig, None) if sig is not None: signal.signal(sig, signal.SIG_DFL) if start_new_session: os.setsid() try: if env is None: os.execvp(executable, args) else: # Python 3.6 started testing for # bytes values in the env; it also # started encoding strs using # fsencode and using a lower-level # API that takes a list of keys # and values. We don't have access # to that API, so we go the reverse direction. env = {os.fsdecode(k) if isinstance(k, bytes) else k: os.fsdecode(v) if isinstance(v, bytes) else v for k, v in env.items()} os.execvpe(executable, args, env) except OSError as e: e._failed_exec = True raise except: exc_type, exc_value, tb = sys.exc_info() # Save the traceback and attach it to the exception object exc_lines = traceback.format_exception(exc_type, exc_value, tb) exc_value.child_traceback = ''.join(exc_lines) os.write(errpipe_write, pickle.dumps(exc_value)) finally: # Make sure that the process exits no matter what. # The return code does not matter much as it won't be # reported to the application os._exit(1) # Parent self._child_created = True if gc_was_enabled: gc.enable() finally: # be sure the FD is closed no matter what os.close(errpipe_write) # self._devnull is not always defined. devnull_fd = getattr(self, '_devnull', None) if p2cread != -1 and p2cwrite != -1 and p2cread != devnull_fd: os.close(p2cread) if c2pwrite != -1 and c2pread != -1 and c2pwrite != devnull_fd: os.close(c2pwrite) if errwrite != -1 and errread != -1 and errwrite != devnull_fd: os.close(errwrite) if devnull_fd is not None: os.close(devnull_fd) # Prevent a double close of these fds from __init__ on error. self._closed_child_pipe_fds = True # Wait for exec to fail or succeed; possibly raising exception errpipe_read = FileObject(errpipe_read, 'rb') data = errpipe_read.read() finally: try: if hasattr(errpipe_read, 'close'): errpipe_read.close() else: os.close(errpipe_read) except OSError: # Especially on PyPy, we sometimes see the above # `os.close(errpipe_read)` raise an OSError. # It's not entirely clear why, but it happens in # InterprocessSignalTests.test_main sometimes, which must mean # we have some sort of race condition. pass finally: errpipe_read = -1 if data != b"": self.wait() child_exception = pickle.loads(data) for fd in (p2cwrite, c2pread, errread): if fd is not None and fd != -1: os.close(fd) if isinstance(child_exception, OSError): child_exception.filename = executable if hasattr(child_exception, '_failed_chdir'): child_exception.filename = cwd if getattr(child_exception, '_failed_chuser', False): child_exception.filename = None > raise child_exception E OSError: [Errno 8] Exec format error: 'locust' /usr/lib/python3/dist-packages/gevent/subprocess.py:1838: OSError _____ DistributedIntegrationTests.test_workers_shut_down_if_master_is_gone _____ self = @unittest.skipIf(os.name == "nt", reason="--processes doesnt work on windows") def test_workers_shut_down_if_master_is_gone(self): content = """ from locust import HttpUser, task, constant, runners runners.MASTER_HEARTBEAT_TIMEOUT = 2 class AnyUser(HttpUser): host = "http://127.0.0.1:8089" wait_time = constant(1) @task def my_task(self): print("worker index:", self.environment.runner.worker_index) """ with mock_locustfile(content=content) as mocked: > master_proc = subprocess.Popen( [ "locust", "-f", mocked.file_path, "--master", "--headless", "--expect-workers", "2", ], stdout=PIPE, stderr=PIPE, text=True, ) locust/test/test_main.py:2115: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3/dist-packages/gevent/subprocess.py:808: in __init__ self._execute_child(args, executable, preexec_fn, close_fds, _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = args = ['locust', '-f', '/build/reproducible-path/locust-2.24.0/locust/test/mock_locustfile_1715256389_7391586_22784.py', '--master', '--headless', '--expect-workers', ...] executable = 'locust', preexec_fn = None, close_fds = True, pass_fds = () cwd = None, env = None, universal_newlines = None, startupinfo = None creationflags = 0, shell = False, p2cread = -1, p2cwrite = -1, c2pread = 11 c2pwrite = 81, errread = 82, errwrite = 83, restore_signals = True, gid = None gids = None, uid = None, umask = -1, start_new_session = False process_group = None def _execute_child(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, universal_newlines, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, restore_signals, gid, gids, uid, umask, start_new_session, process_group): """Execute program (POSIX version)""" if isinstance(args, (str, bytes)): args = [args] elif isinstance(args, PathLike): if shell: raise TypeError('path-like args is not allowed when ' 'shell is true') args = [fsencode(args)] # os.PathLike -> [str] else: args = list(args) if shell: # On Android the default shell is at '/system/bin/sh'. unix_shell = ( '/system/bin/sh' if hasattr(sys, 'getandroidapilevel') else '/bin/sh' ) args = [unix_shell, "-c"] + args if executable: args[0] = executable if executable is None: executable = args[0] self._loop.install_sigchld() # For transferring possible exec failure from child to parent # The first char specifies the exception type: 0 means # OSError, 1 means some other error. errpipe_read, errpipe_write = self.pipe_cloexec() # errpipe_write must not be in the standard io 0, 1, or 2 fd range. low_fds_to_close = [] while errpipe_write < 3: low_fds_to_close.append(errpipe_write) errpipe_write = os.dup(errpipe_write) for low_fd in low_fds_to_close: os.close(low_fd) try: try: gc_was_enabled = gc.isenabled() # Disable gc to avoid bug where gc -> file_dealloc -> # write to stderr -> hang. http://bugs.python.org/issue1336 gc.disable() try: self.pid = fork_and_watch(self._on_child, self._loop, True, fork) except: if gc_was_enabled: gc.enable() raise if self.pid == 0: # Child # In various places on the child side of things, we catch OSError # and add attributes to it that detail where in the process we failed; # like all exceptions until we have exec'd, this exception is pickled # and sent to the parent to raise in the calling process. # The parent uses this to decide how to treat that exception, # adjusting certain information about it as needed. # # Python 3.11.8 --- yes, a minor patch release --- stopped # letting the 'filename' parameter get set in the resulting # exception for many cases. We're not quite interpreting this # the same way the stdlib is, I'm sure, but this makes the stdlib # tests pass. # XXX: Technically we're doing a lot of stuff here that # may not be safe to do before a exec(), depending on the OS. # CPython 3 goes to great lengths to precompute a lot # of this info before the fork and pass it all to C functions that # try hard not to call things like malloc(). (Of course, # CPython 2 pretty much did what we're doing.) try: # Close parent's pipe ends if p2cwrite != -1: os.close(p2cwrite) if c2pread != -1: os.close(c2pread) if errread != -1: os.close(errread) os.close(errpipe_read) # When duping fds, if there arises a situation # where one of the fds is either 0, 1 or 2, it # is possible that it is overwritten (#12607). if c2pwrite == 0: c2pwrite = os.dup(c2pwrite) _set_inheritable(c2pwrite, False) while errwrite in (0, 1): errwrite = os.dup(errwrite) _set_inheritable(errwrite, False) # Dup fds for child def _dup2(existing, desired): # dup2() removes the CLOEXEC flag but # we must do it ourselves if dup2() # would be a no-op (issue #10806). if existing == desired: self._set_cloexec_flag(existing, False) elif existing != -1: os.dup2(existing, desired) try: self._remove_nonblock_flag(desired) except OSError: # Ignore EBADF, it may not actually be # open yet. # Tested beginning in 3.7.0b3 test_subprocess.py pass _dup2(p2cread, 0) _dup2(c2pwrite, 1) _dup2(errwrite, 2) # Close pipe fds. Make sure we don't close the # same fd more than once, or standard fds. if not True: closed = set([None]) for fd in (p2cread, c2pwrite, errwrite): if fd not in closed and fd > 2: os.close(fd) closed.add(fd) # Python 3 (with a working set_inheritable): # We no longer manually close p2cread, # c2pwrite, and errwrite here as # _close_open_fds takes care when it is # not already non-inheritable. if cwd is not None: try: os.chdir(cwd) except OSError as e: e._failed_chdir = True raise # Python 3.9 if umask >= 0: os.umask(umask) # XXX: CPython does _Py_RestoreSignals here. # Then setsid() based on ??? try: if gids: os.setgroups(gids) if gid: os.setregid(gid, gid) if uid: os.setreuid(uid, uid) if process_group is not None: os.setpgid(0, process_group) except OSError as e: e._failed_chuser = True raise if preexec_fn: preexec_fn() # Close all other fds, if asked for. This must be done # after preexec_fn runs. if close_fds: fds_to_keep = set(pass_fds) fds_to_keep.add(errpipe_write) self._close_fds(fds_to_keep, errpipe_write) if restore_signals: # restore the documented signals back to sig_dfl; # not all will be defined on every platform for sig in 'SIGPIPE', 'SIGXFZ', 'SIGXFSZ': sig = getattr(signal, sig, None) if sig is not None: signal.signal(sig, signal.SIG_DFL) if start_new_session: os.setsid() try: if env is None: os.execvp(executable, args) else: # Python 3.6 started testing for # bytes values in the env; it also # started encoding strs using # fsencode and using a lower-level # API that takes a list of keys # and values. We don't have access # to that API, so we go the reverse direction. env = {os.fsdecode(k) if isinstance(k, bytes) else k: os.fsdecode(v) if isinstance(v, bytes) else v for k, v in env.items()} os.execvpe(executable, args, env) except OSError as e: e._failed_exec = True raise except: exc_type, exc_value, tb = sys.exc_info() # Save the traceback and attach it to the exception object exc_lines = traceback.format_exception(exc_type, exc_value, tb) exc_value.child_traceback = ''.join(exc_lines) os.write(errpipe_write, pickle.dumps(exc_value)) finally: # Make sure that the process exits no matter what. # The return code does not matter much as it won't be # reported to the application os._exit(1) # Parent self._child_created = True if gc_was_enabled: gc.enable() finally: # be sure the FD is closed no matter what os.close(errpipe_write) # self._devnull is not always defined. devnull_fd = getattr(self, '_devnull', None) if p2cread != -1 and p2cwrite != -1 and p2cread != devnull_fd: os.close(p2cread) if c2pwrite != -1 and c2pread != -1 and c2pwrite != devnull_fd: os.close(c2pwrite) if errwrite != -1 and errread != -1 and errwrite != devnull_fd: os.close(errwrite) if devnull_fd is not None: os.close(devnull_fd) # Prevent a double close of these fds from __init__ on error. self._closed_child_pipe_fds = True # Wait for exec to fail or succeed; possibly raising exception errpipe_read = FileObject(errpipe_read, 'rb') data = errpipe_read.read() finally: try: if hasattr(errpipe_read, 'close'): errpipe_read.close() else: os.close(errpipe_read) except OSError: # Especially on PyPy, we sometimes see the above # `os.close(errpipe_read)` raise an OSError. # It's not entirely clear why, but it happens in # InterprocessSignalTests.test_main sometimes, which must mean # we have some sort of race condition. pass finally: errpipe_read = -1 if data != b"": self.wait() child_exception = pickle.loads(data) for fd in (p2cwrite, c2pread, errread): if fd is not None and fd != -1: os.close(fd) if isinstance(child_exception, OSError): child_exception.filename = executable if hasattr(child_exception, '_failed_chdir'): child_exception.filename = cwd if getattr(child_exception, '_failed_chuser', False): child_exception.filename = None > raise child_exception E OSError: [Errno 8] Exec format error: 'locust' /usr/lib/python3/dist-packages/gevent/subprocess.py:1838: OSError ______________________ TestLocustRunner.test_cpu_warning _______________________ self = def test_cpu_warning(self): _monitor_interval = runners.CPU_MONITOR_INTERVAL runners.CPU_MONITOR_INTERVAL = 2.0 try: class CpuUser(User): wait_time = constant(0.001) @task def cpu_task(self): for i in range(1000000): _ = 3 / 2 environment = Environment(user_classes=[CpuUser]) environment._cpu_warning_event_triggered = False def cpu_warning(environment, cpu_usage, **kwargs): environment._cpu_warning_event_triggered = True environment._cpu_usage = cpu_usage environment.events.cpu_warning.add_listener(cpu_warning) runner = LocalRunner(environment) self.assertFalse(runner.cpu_warning_emitted) runner.spawn_users({CpuUser.__name__: 1}, wait=False) sleep(2.5) > self.assertTrue(environment._cpu_warning_event_triggered) E AssertionError: False is not true locust/test/test_runners.py:172: AssertionError _______________ TestLocustRunner.test_stop_users_with_spawn_rate _______________ self = def test_stop_users_with_spawn_rate(self): """ The spawn rate does not have an effect on the rate at which the users are stopped. It is expected that the excess users will be stopped as soon as possible in parallel (while respecting the stop_timeout). """ class MyUser(User): wait_time = constant(1) @task def my_task(self): pass environment = Environment(user_classes=[MyUser]) runner = LocalRunner(environment) # Start load test, wait for users to start, then trigger ramp down ts = time.time() runner.start(10, 10, wait=False) runner.spawning_greenlet.join() delta = time.time() - ts self.assertTrue( 0 <= delta <= 0.05, f"Expected user count to increase to 10 instantaneously, instead it took {delta:f}" ) self.assertTrue( runner.user_count == 10, "User count has not decreased correctly to 2, it is : %i" % runner.user_count ) ts = time.time() runner.start(2, 4, wait=False) runner.spawning_greenlet.join() delta = time.time() - ts > self.assertTrue(0 <= delta <= 1.05, f"Expected user count to decrease to 2 in 1s, instead it took {delta:f}") E AssertionError: False is not true : Expected user count to decrease to 2 in 1s, instead it took 1.093991 locust/test/test_runners.py:492: AssertionError ------------------------------ Captured log call ------------------------------- INFO locust.runners:runners.py:499 Ramping to 10 users at a rate of 10.00 per second INFO locust.runners:runners.py:537 All users spawned: {"MyUser": 10} (10 total users) INFO locust.runners:runners.py:499 Ramping to 2 users at a rate of 4.00 per second INFO locust.runners:runners.py:537 All users spawned: {"MyUser": 2} (2 total users) ________ TestMasterRunner.test_attributes_populated_when_calling_start _________ self = def test_attributes_populated_when_calling_start(self): class MyUser1(User): @task def my_task(self): pass class MyUser2(User): @task def my_task(self): pass with mock.patch("locust.rpc.rpc.Server", mocked_rpc()) as server: master = self.get_runner(user_classes=[MyUser1, MyUser2]) server.mocked_send(Message("client_ready", __version__, "fake_client1")) master.start(7, 7) > self.assertEqual({"MyUser1": 4, "MyUser2": 3}, master.target_user_classes_count) E AssertionError: {'MyUser1': 4, 'MyUser2': 3} != {} E - {'MyUser1': 4, 'MyUser2': 3} E + {} locust/test/test_runners.py:3033: AssertionError ------------------------------ Captured log call ------------------------------- ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (fake_client1). That's not going to work. WARNING locust.runners:runners.py:743 You can't start a distributed test before at least one worker processes has connected ________________ TestMasterRunner.test_custom_shape_scale_down _________________ self = def test_custom_shape_scale_down(self): class MyUser(User): @task def my_task(self): pass class TestShape(LoadTestShape): def tick(self): run_time = self.get_run_time() if run_time < 2: return 5, 5 elif run_time < 4: return 1, 5 else: return None self.environment.shape_class = TestShape() with mock.patch("locust.rpc.rpc.Server", mocked_rpc()) as server: master = self.get_runner(user_classes=[MyUser]) for i in range(5): server.mocked_send(Message("client_ready", __version__, "fake_client%i" % i)) # Start the shape_worker self.environment.shape_class.reset_time() master.start_shape() sleep(0.5) # Wait for shape_worker to update user_count num_users = sum( sum(msg.data["user_classes_count"].values()) for _, msg in server.outbox if msg.type != "ack" ) > self.assertEqual( 5, num_users, "Total number of users in first stage of shape test is not 5: %i" % num_users ) E AssertionError: 5 != 0 : Total number of users in first stage of shape test is not 5: 0 locust/test/test_runners.py:2907: AssertionError ------------------------------ Captured log call ------------------------------- ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (fake_client0). That's not going to work. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (fake_client1). That's not going to work. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (fake_client2). That's not going to work. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (fake_client3). That's not going to work. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (fake_client4). That's not going to work. INFO locust.runners:runners.py:329 Shape test starting. INFO locust.runners:runners.py:337 Shape worker starting INFO locust.runners:runners.py:356 Shape test updating to 5 users at 5.00 spawn rate WARNING locust.runners:runners.py:743 You can't start a distributed test before at least one worker processes has connected ______________ TestMasterRunner.test_custom_shape_scale_interval _______________ self = def test_custom_shape_scale_interval(self): class MyUser(User): @task def my_task(self): pass class TestShape(LoadTestShape): def __init__(self): super().__init__() self._users_num = [1, 1, 1, 2, 2, 3, 3, 3, 4] self._index = 0 def tick(self): if self._index >= len(self._users_num): return None users_num = self._users_num[self._index] self._index += 1 return users_num, users_num self.environment.shape_class = TestShape() with mock.patch("locust.rpc.rpc.Server", mocked_rpc()) as server: master = self.get_runner(user_classes=[MyUser]) for i in range(5): server.mocked_send(Message("client_ready", __version__, "fake_client%i" % i)) # Start the shape_worker self.environment.shape_class.reset_time() master.start_shape() # Wait for shape_worker to update user_count sleep(0.5) num_users = sum( sum(msg.data["user_classes_count"].values()) for _, msg in server.outbox if msg.type != "ack" ) > self.assertEqual( 1, num_users, "Total number of users in first stage of shape test is not 1: %i" % num_users ) E AssertionError: 1 != 0 : Total number of users in first stage of shape test is not 1: 0 locust/test/test_runners.py:2800: AssertionError ------------------------------ Captured log call ------------------------------- ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (fake_client0). That's not going to work. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (fake_client1). That's not going to work. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (fake_client2). That's not going to work. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (fake_client3). That's not going to work. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (fake_client4). That's not going to work. INFO locust.runners:runners.py:329 Shape test starting. INFO locust.runners:runners.py:337 Shape worker starting INFO locust.runners:runners.py:356 Shape test updating to 1 users at 1.00 spawn rate WARNING locust.runners:runners.py:743 You can't start a distributed test before at least one worker processes has connected _________________ TestMasterRunner.test_custom_shape_scale_up __________________ self = def test_custom_shape_scale_up(self): class MyUser(User): @task def my_task(self): pass class TestShape(LoadTestShape): def tick(self): run_time = self.get_run_time() if run_time < 2: return 1, 1 elif run_time < 4: return 2, 2 else: return None self.environment.shape_class = TestShape() with mock.patch("locust.rpc.rpc.Server", mocked_rpc()) as server: master = self.get_runner(user_classes=[MyUser]) for i in range(5): server.mocked_send(Message("client_ready", __version__, "fake_client%i" % i)) # Start the shape_worker self.environment.shape_class.reset_time() master.start_shape() sleep(0.5) # Wait for shape_worker to update user_count num_users = sum( sum(msg.data["user_classes_count"].values()) for _, msg in server.outbox if msg.type != "ack" ) > self.assertEqual( 1, num_users, "Total number of users in first stage of shape test is not 1: %i" % num_users ) E AssertionError: 1 != 0 : Total number of users in first stage of shape test is not 1: 0 locust/test/test_runners.py:2858: AssertionError ------------------------------ Captured log call ------------------------------- ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (fake_client0). That's not going to work. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (fake_client1). That's not going to work. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (fake_client2). That's not going to work. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (fake_client3). That's not going to work. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (fake_client4). That's not going to work. INFO locust.runners:runners.py:329 Shape test starting. INFO locust.runners:runners.py:337 Shape worker starting INFO locust.runners:runners.py:356 Shape test updating to 1 users at 1.00 spawn rate WARNING locust.runners:runners.py:743 You can't start a distributed test before at least one worker processes has connected INFO locust.runners:runners.py:356 Shape test updating to 1 users at 5.00 spawn rate WARNING locust.runners:runners.py:743 You can't start a distributed test before at least one worker processes has connected _____________ TestMasterRunner.test_last_worker_missing_stops_test _____________ self = @mock.patch("locust.runners.HEARTBEAT_INTERVAL", new=0.1) def test_last_worker_missing_stops_test(self): class TestUser(User): @task def my_task(self): gevent.sleep(600) with mock.patch("locust.rpc.rpc.Server", mocked_rpc()) as server, patch_env( "LOCUST_WAIT_FOR_WORKERS_REPORT_AFTER_RAMP_UP", "0.1" ): master = self.get_runner(user_classes=[TestUser]) server.mocked_send(Message("client_ready", __version__, "fake_client1")) server.mocked_send(Message("client_ready", __version__, "fake_client2")) server.mocked_send(Message("client_ready", __version__, "fake_client3")) master.start(3, 3) server.mocked_send(Message("spawning", None, "fake_client1")) server.mocked_send(Message("spawning", None, "fake_client2")) server.mocked_send(Message("spawning", None, "fake_client3")) sleep(0.2) server.mocked_send( Message( "heartbeat", {"state": STATE_RUNNING, "current_cpu_usage": 50, "current_memory_usage": 200, "count": 1}, "fake_client1", ) ) server.mocked_send( Message( "heartbeat", {"state": STATE_RUNNING, "current_cpu_usage": 50, "current_memory_usage": 200, "count": 1}, "fake_client2", ) ) server.mocked_send( Message( "heartbeat", {"state": STATE_RUNNING, "current_cpu_usage": 50, "current_memory_usage": 200, "count": 1}, "fake_client3", ) ) sleep(0.2) self.assertEqual(0, len(master.clients.missing)) > self.assertEqual(3, master.worker_count) E AssertionError: 3 != 0 locust/test/test_runners.py:2236: AssertionError ------------------------------ Captured log call ------------------------------- ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (fake_client1). That's not going to work. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (fake_client2). That's not going to work. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (fake_client3). That's not going to work. WARNING locust.runners:runners.py:743 You can't start a distributed test before at least one worker processes has connected WARNING locust.runners:runners.py:1115 Got spawning message from unknown worker fake_client1. Asking worker to quit. WARNING locust.runners:runners.py:1115 Got spawning message from unknown worker fake_client2. Asking worker to quit. WARNING locust.runners:runners.py:1115 Got spawning message from unknown worker fake_client3. Asking worker to quit. INFO locust.runners:runners.py:933 Worker 0 failed to send heartbeat, setting state to missing. INFO locust.runners:runners.py:933 Worker 1 failed to send heartbeat, setting state to missing. INFO locust.runners:runners.py:933 Worker 2 failed to send heartbeat, setting state to missing. INFO locust.runners:runners.py:933 Worker 3 failed to send heartbeat, setting state to missing. INFO locust.runners:runners.py:933 Worker 4 failed to send heartbeat, setting state to missing. INFO locust.runners:runners.py:941 The last worker went missing, stopping test. ____________ TestMasterRunner.test_last_worker_quitting_stops_test _____________ self = def test_last_worker_quitting_stops_test(self): class TestUser(User): @task def my_task(self): gevent.sleep(600) with mock.patch("locust.rpc.rpc.Server", mocked_rpc()) as server, patch_env( "LOCUST_WAIT_FOR_WORKERS_REPORT_AFTER_RAMP_UP", "0.1" ): master = self.get_runner(user_classes=[TestUser]) server.mocked_send(Message("client_ready", __version__, "fake_client1")) server.mocked_send(Message("client_ready", __version__, "fake_client2")) master.start(1, 2) server.mocked_send(Message("spawning", None, "fake_client1")) server.mocked_send(Message("spawning", None, "fake_client2")) server.mocked_send(Message("quit", None, "fake_client1")) sleep(0.1) > self.assertEqual(1, len(master.clients.all)) E AssertionError: 1 != 0 locust/test/test_runners.py:2183: AssertionError ------------------------------ Captured log call ------------------------------- ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (fake_client1). That's not going to work. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (fake_client2). That's not going to work. WARNING locust.runners:runners.py:743 You can't start a distributed test before at least one worker processes has connected WARNING locust.runners:runners.py:1115 Got spawning message from unknown worker fake_client1. Asking worker to quit. WARNING locust.runners:runners.py:1115 Got spawning message from unknown worker fake_client2. Asking worker to quit. INFO locust.runners:runners.py:356 Shape test updating to 2 users at 2.00 spawn rate WARNING locust.runners:runners.py:743 You can't start a distributed test before at least one worker processes has connected INFO locust.runners:runners.py:356 Shape test updating to 2 users at 2.00 spawn rate WARNING locust.runners:runners.py:743 You can't start a distributed test before at least one worker processes has connected ___________ TestMasterRunner.test_master_discard_first_client_ready ____________ self = def test_master_discard_first_client_ready(self): with mock.patch("locust.rpc.rpc.Server", mocked_rpc()) as server: server.mocked_send(Message("client_ready", __version__, "dummy_client")) # discard first client_ready msg server.queue.get() master = self.get_runner() server.mocked_send(Message("client_ready", __version__, "dummy_client")) > self.assertEqual(1, len(master.clients)) E AssertionError: 1 != 0 locust/test/test_runners.py:3148: AssertionError ------------------------------ Captured log call ------------------------------- ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (dummy_client). That's not going to work. _________ TestMasterRunner.test_master_marks_downed_workers_as_missing _________ self = def test_master_marks_downed_workers_as_missing(self): with mock.patch("locust.rpc.rpc.Server", mocked_rpc()) as server: master = self.get_runner() server.mocked_send(Message("client_ready", __version__, "fake_client")) sleep(6) # print(master.clients['fake_client'].__dict__) > assert master.clients["fake_client"].state == STATE_MISSING locust/test/test_runners.py:2162: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = , k = 'fake_client' def __getitem__(self, k: str) -> WorkerNode: > return self._worker_nodes[k] E KeyError: 'fake_client' locust/runners.py:636: KeyError ------------------------------ Captured log call ------------------------------- ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (fake_client). That's not going to work. INFO locust.runners:runners.py:342 Shape test stopping INFO locust.runners:runners.py:342 Shape test stopping INFO locust.runners:runners.py:356 Shape test updating to 3 users at 3.00 spawn rate WARNING locust.runners:runners.py:743 You can't start a distributed test before at least one worker processes has connected INFO locust.runners:runners.py:356 Shape test updating to 4 users at 4.00 spawn rate WARNING locust.runners:runners.py:743 You can't start a distributed test before at least one worker processes has connected INFO locust.runners:runners.py:342 Shape test stopping ________________ TestMasterRunner.test_master_reset_connection _________________ self = def test_master_reset_connection(self): """Test that connection will be reset when network issues found""" with mock.patch("locust.runners.FALLBACK_INTERVAL", new=0.1): with mock.patch("locust.rpc.rpc.Server", mocked_rpc(raise_on_close=False)) as server: master = self.get_runner() self.assertEqual(0, len(master.clients)) server.mocked_send(Message("client_ready", NETWORK_BROKEN, "fake_client")) self.assertTrue(master.connection_broken) server.mocked_send(Message("client_ready", __version__, "fake_client")) sleep(1) self.assertFalse(master.connection_broken) > self.assertEqual(1, len(master.clients)) E AssertionError: 1 != 0 locust/test/test_runners.py:2998: AssertionError ------------------------------ Captured log call ------------------------------- ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (fake_client). That's not going to work. INFO locust.runners:runners.py:959 Resetting RPC server and all worker connections. ________ TestMasterRunner.test_rebalance_locust_users_on_worker_connect ________ self = @mock.patch("locust.runners.HEARTBEAT_INTERVAL", new=600) def test_rebalance_locust_users_on_worker_connect(self): class TestUser(User): @task def my_task(self): pass with mock.patch("locust.rpc.rpc.Server", mocked_rpc()) as server: master = self.get_runner(user_classes=[TestUser]) server.mocked_send(Message("client_ready", __version__, "zeh_fake_client1")) > self.assertEqual(1, len(master.clients)) E AssertionError: 1 != 0 locust/test/test_runners.py:2511: AssertionError ------------------------------ Captured log call ------------------------------- ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (zeh_fake_client1). That's not going to work. ____________ TestMasterRunner.test_reset_connection_after_RPCError _____________ self = def test_reset_connection_after_RPCError(self): with mock.patch("locust.rpc.rpc.Server", mocked_rpc(raise_on_close=False)) as server: master = self.get_runner() server.mocked_send(Message("client_ready", __version__, "fake_client")) sleep(0.2) self.assertFalse(master.connection_broken) > self.assertEqual(1, len(master.clients)) E AssertionError: 1 != 0 locust/test/test_runners.py:3007: AssertionError ------------------------------ Captured log call ------------------------------- ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (fake_client). That's not going to work. ______________ TestMasterRunner.test_spawn_correct_worker_indexes ______________ self = def test_spawn_correct_worker_indexes(self): """ Tests that workers would receive a monotonic sequence of ordinal IDs. """ class TestUser(User): @task def my_task(self): pass with mock.patch("locust.rpc.rpc.Server", mocked_rpc()) as server: master = self.get_runner(user_classes=[TestUser]) USERS_COUNT = 5 for i in range(USERS_COUNT): server.mocked_send(Message("client_ready", __version__, "fake_client%i" % i)) master.start(USERS_COUNT, USERS_COUNT) > self.assertEqual(USERS_COUNT * 2, len(server.outbox)) E AssertionError: 10 != 0 locust/test/test_runners.py:2753: AssertionError ------------------------------ Captured log call ------------------------------- ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (fake_client0). That's not going to work. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (fake_client1). That's not going to work. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (fake_client2). That's not going to work. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (fake_client3). That's not going to work. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (fake_client4). That's not going to work. WARNING locust.runners:runners.py:743 You can't start a distributed test before at least one worker processes has connected ____________ TestMasterRunner.test_spawn_fewer_locusts_than_workers ____________ self = def test_spawn_fewer_locusts_than_workers(self): class TestUser(User): @task def my_task(self): pass with mock.patch("locust.rpc.rpc.Server", mocked_rpc()) as server: master = self.get_runner(user_classes=[TestUser]) for i in range(5): server.mocked_send(Message("client_ready", __version__, "fake_client%i" % i)) master.start(2, 2) > self.assertEqual(10, len(server.outbox)) E AssertionError: 10 != 0 locust/test/test_runners.py:2726: AssertionError ------------------------------ Captured log call ------------------------------- ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (fake_client0). That's not going to work. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (fake_client1). That's not going to work. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (fake_client2). That's not going to work. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (fake_client3). That's not going to work. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (fake_client4). That's not going to work. WARNING locust.runners:runners.py:743 You can't start a distributed test before at least one worker processes has connected __________________ TestMasterRunner.test_spawn_uneven_locusts __________________ self = def test_spawn_uneven_locusts(self): """ Tests that we can accurately spawn a certain number of locusts, even if it's not an even number of the connected workers """ class TestUser(User): @task def my_task(self): pass with mock.patch("locust.rpc.rpc.Server", mocked_rpc()) as server: master = self.get_runner(user_classes=[TestUser]) for i in range(5): server.mocked_send(Message("client_ready", __version__, "fake_client%i" % i)) master.start(7, 7) > self.assertEqual(10, len(server.outbox)) E AssertionError: 10 != 0 locust/test/test_runners.py:2705: AssertionError ------------------------------ Captured log call ------------------------------- ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (fake_client0). That's not going to work. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (fake_client1). That's not going to work. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (fake_client2). That's not going to work. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (fake_client3). That's not going to work. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (fake_client4). That's not going to work. WARNING locust.runners:runners.py:743 You can't start a distributed test before at least one worker processes has connected ______________________ TestMasterRunner.test_start_event _______________________ self = def test_start_event(self): """ Tests that test_start event is fired """ class TestUser(User): @task def my_task(self): pass with mock.patch("locust.rpc.rpc.Server", mocked_rpc()) as server: master = self.get_runner(user_classes=[TestUser]) run_count = [0] @self.environment.events.test_start.add_listener def on_test_start(*a, **kw): run_count[0] += 1 for i in range(5): server.mocked_send(Message("client_ready", __version__, "fake_client%i" % i)) master.start(7, 7) > self.assertEqual(10, len(server.outbox)) E AssertionError: 10 != 0 locust/test/test_runners.py:2580: AssertionError ------------------------------ Captured log call ------------------------------- ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (fake_client0). That's not going to work. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (fake_client1). That's not going to work. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (fake_client2). That's not going to work. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (fake_client3). That's not going to work. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (fake_client4). That's not going to work. WARNING locust.runners:runners.py:743 You can't start a distributed test before at least one worker processes has connected _______________________ TestMasterRunner.test_stop_event _______________________ self = def test_stop_event(self): """ Tests that test_stop event is fired """ class TestUser(User): @task def my_task(self): pass with mock.patch("locust.rpc.rpc.Server", mocked_rpc()) as server: master = self.get_runner(user_classes=[TestUser]) @self.environment.events.test_stopping.add_listener def on_test_stopping(*_, **__): self.runner_stopping = True @self.environment.events.test_stop.add_listener def on_test_stop(*_, **__): self.runner_stopped = True for i in range(5): server.mocked_send(Message("client_ready", __version__, "fake_client%i" % i)) master.start(7, 7) > self.assertEqual(10, len(server.outbox)) E AssertionError: 10 != 0 locust/test/test_runners.py:2619: AssertionError ------------------------------ Captured log call ------------------------------- ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (fake_client0). That's not going to work. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (fake_client1). That's not going to work. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (fake_client2). That's not going to work. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (fake_client3). That's not going to work. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (fake_client4). That's not going to work. WARNING locust.runners:runners.py:743 You can't start a distributed test before at least one worker processes has connected ____________________ TestMasterRunner.test_stop_event_quit _____________________ self = def test_stop_event_quit(self): """ Tests that test_stop event is fired when quit() is called directly """ class TestUser(User): @task def my_task(self): pass with mock.patch("locust.rpc.rpc.Server", mocked_rpc()) as server: master = self.get_runner(user_classes=[TestUser]) @self.environment.events.test_stopping.add_listener def on_test_stopping(*_, **__): self.runner_stopping = True @self.environment.events.test_stop.add_listener def on_test_stop(*_, **__): self.runner_stopped = True for i in range(5): server.mocked_send(Message("client_ready", __version__, "fake_client%i" % i)) master.start(7, 7) > self.assertEqual(10, len(server.outbox)) E AssertionError: 10 != 0 locust/test/test_runners.py:2658: AssertionError ------------------------------ Captured log call ------------------------------- ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (fake_client0). That's not going to work. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (fake_client1). That's not going to work. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (fake_client2). That's not going to work. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (fake_client3). That's not going to work. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (fake_client4). That's not going to work. WARNING locust.runners:runners.py:743 You can't start a distributed test before at least one worker processes has connected __________ TestMasterRunner.test_unknown_host_sends_message_to_master __________ self = def test_unknown_host_sends_message_to_master(self): """ Validate master ignores message that is sent from unknown host """ class TestUser(User): @task def my_task(self): pass with mock.patch("locust.rpc.rpc.Server", mocked_rpc()) as server: master = self.get_runner(user_classes=[TestUser]) server.mocked_send(Message("client_ready", __version__, "zeh_fake_client1")) > self.assertEqual(1, len(master.clients)) E AssertionError: 1 != 0 locust/test/test_runners.py:3217: AssertionError ------------------------------ Captured log call ------------------------------- ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (zeh_fake_client1). That's not going to work. _____________________ TestMasterRunner.test_worker_connect _____________________ self = def test_worker_connect(self): with mock.patch("locust.rpc.rpc.Server", mocked_rpc()) as server: master = self.get_runner() server.mocked_send(Message("client_ready", __version__, "zeh_fake_client1")) > self.assertEqual(1, len(master.clients)) E AssertionError: 1 != 0 locust/test/test_runners.py:2083: AssertionError ------------------------------ Captured log call ------------------------------- ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (zeh_fake_client1). That's not going to work. __________ TestMasterRunner.test_worker_connect_with_special_versions __________ self = def test_worker_connect_with_special_versions(self): with mock.patch("locust.rpc.rpc.Server", mocked_rpc()) as server: master = self.get_runner() server.mocked_send(Message("client_ready", None, "1.x_style_client_should_not_be_allowed")) self.assertEqual(1, len(self.mocked_log.error)) self.assertEqual(0, len(master.clients)) server.mocked_send(Message("client_ready", "abcd", "other_version_mismatch_should_just_give_a_warning")) self.assertEqual(1, len(self.mocked_log.warning)) self.assertEqual(1, len(master.clients)) server.mocked_send(Message("client_ready", -1, "version_check_bypass_should_not_warn")) self.assertEqual(1, len(self.mocked_log.warning)) self.assertEqual(2, len(master.clients)) server.mocked_send( Message("client_ready", __version__ + "1", "difference_in_patch_version_should_not_warn") ) self.assertEqual(3, len(master.clients)) > self.assertEqual(1, len(self.mocked_log.warning)) E AssertionError: 1 != 2 locust/test/test_runners.py:2111: AssertionError ------------------------------ Captured log call ------------------------------- ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (1.x_style_client_should_not_be_allowed). That's not going to work. WARNING locust.runners:runners.py:1017 A worker (other_version_mismatch_should_just_give_a_warning) running a different version (abcd) connected, master version is INFO locust.runners:runners.py:1028 Worker other_version_mismatch_should_just_give_a_warning (index 0) reported as ready. 1 workers connected. INFO locust.runners:runners.py:1028 Worker version_check_bypass_should_not_warn (index 1) reported as ready. 2 workers connected. WARNING locust.runners:runners.py:1017 A worker (difference_in_patch_version_should_not_warn) running a different version (1) connected, master version is INFO locust.runners:runners.py:1028 Worker difference_in_patch_version_should_not_warn (index 2) reported as ready. 3 workers connected. ______ TestMasterRunner.test_worker_missing_after_heartbeat_dead_interval ______ self = @mock.patch("locust.runners.HEARTBEAT_INTERVAL", new=0.1) @mock.patch("locust.runners.HEARTBEAT_DEAD_INTERNAL", new=-3) def test_worker_missing_after_heartbeat_dead_interval(self): class TestUser(User): @task def my_task(self): gevent.sleep(600) with mock.patch("locust.rpc.rpc.Server", mocked_rpc()) as server, patch_env( "LOCUST_WAIT_FOR_WORKERS_REPORT_AFTER_RAMP_UP", "0.1" ): master = self.get_runner(user_classes=[TestUser]) server.mocked_send(Message("client_ready", __version__, "fake_client1")) server.mocked_send(Message("client_ready", __version__, "fake_client2")) server.mocked_send(Message("client_ready", __version__, "fake_client3")) master.start(3, 3) server.mocked_send(Message("spawning", None, "fake_client1")) server.mocked_send(Message("spawning", None, "fake_client2")) server.mocked_send(Message("spawning", None, "fake_client3")) sleep(0.1) server.mocked_send( Message( "heartbeat", {"state": STATE_RUNNING, "current_cpu_usage": 50, "current_memory_usage": 200, "count": 1}, "fake_client1", ) ) server.mocked_send( Message( "heartbeat", {"state": STATE_RUNNING, "current_cpu_usage": 50, "current_memory_usage": 200, "count": 1}, "fake_client2", ) ) server.mocked_send( Message( "heartbeat", {"state": STATE_RUNNING, "current_cpu_usage": 50, "current_memory_usage": 200, "count": 1}, "fake_client3", ) ) sleep(0.1) # initially all workers are in active state self.assertEqual(0, len(master.clients.missing)) > self.assertEqual(3, master.worker_count) E AssertionError: 3 != 0 locust/test/test_runners.py:2308: AssertionError ------------------------------ Captured log call ------------------------------- ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (fake_client1). That's not going to work. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (fake_client2). That's not going to work. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (fake_client3). That's not going to work. WARNING locust.runners:runners.py:743 You can't start a distributed test before at least one worker processes has connected WARNING locust.runners:runners.py:1115 Got spawning message from unknown worker fake_client1. Asking worker to quit. WARNING locust.runners:runners.py:1115 Got spawning message from unknown worker fake_client2. Asking worker to quit. WARNING locust.runners:runners.py:1115 Got spawning message from unknown worker fake_client3. Asking worker to quit. ___________ TestMasterRunner.test_worker_sends_bad_message_to_master ___________ self = def test_worker_sends_bad_message_to_master(self): """ Validate master sends reconnect message to worker when it receives a bad message. """ class TestUser(User): @task def my_task(self): pass with mock.patch("locust.rpc.rpc.Server", mocked_rpc()) as server: master = self.get_runner(user_classes=[TestUser]) server.mocked_send(Message("client_ready", __version__, "zeh_fake_client1")) > self.assertEqual(1, len(master.clients)) E AssertionError: 1 != 0 locust/test/test_runners.py:3166: AssertionError ------------------------------ Captured log call ------------------------------- ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (zeh_fake_client1). That's not going to work. ______ TestMasterRunner.test_worker_sends_unrecognized_message_to_master _______ self = def test_worker_sends_unrecognized_message_to_master(self): """ Validate master ignores message from worker when it cannot parse adddress info. """ class TestUser(User): @task def my_task(self): pass with mock.patch("locust.rpc.rpc.Server", mocked_rpc()) as server: master = self.get_runner(user_classes=[TestUser]) server.mocked_send(Message("client_ready", __version__, "zeh_fake_client1")) > self.assertEqual(1, len(master.clients)) E AssertionError: 1 != 0 locust/test/test_runners.py:3194: AssertionError ------------------------------ Captured log call ------------------------------- ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (zeh_fake_client1). That's not going to work. _____________ TestStopTimeout.test_kill_locusts_with_stop_timeout ______________ self = def test_kill_locusts_with_stop_timeout(self): short_time = 0.05 class MyTaskSet(TaskSet): @task def my_task(self): MyTaskSet.state = "first" gevent.sleep(short_time) MyTaskSet.state = "second" # should only run when run time + stop_timeout is > short_time gevent.sleep(short_time) MyTaskSet.state = "third" # should only run when run time + stop_timeout is > short_time * 2 class MyTestUser(User): tasks = [MyTaskSet] environment = create_environment([MyTestUser], mocked_options()) runner = environment.create_local_runner() runner.start(1, 1) gevent.sleep(short_time / 2) runner.stop_users({MyTestUser.__name__: 1}) > self.assertEqual("first", MyTaskSet.state) E AssertionError: 'first' != 'third' E - first E + third locust/test/test_runners.py:4105: AssertionError ------------------------------ Captured log call ------------------------------- INFO locust.runners:runners.py:499 Ramping to 1 users at a rate of 1.00 per second INFO locust.runners:runners.py:537 All users spawned: {"MyTestUser": 1} (1 total users) INFO locust.runners:runners.py:141 Resetting stats ______________________ TestStopTimeout.test_stop_timeout _______________________ self = def test_stop_timeout(self): short_time = 0.05 class MyTaskSet(TaskSet): @task def my_task(self): MyTaskSet.state = "first" gevent.sleep(short_time) MyTaskSet.state = "second" # should only run when run time + stop_timeout is > short_time gevent.sleep(short_time) MyTaskSet.state = "third" # should only run when run time + stop_timeout is > short_time * 2 class MyTestUser(User): tasks = [MyTaskSet] environment = Environment(user_classes=[MyTestUser]) runner = environment.create_local_runner() runner.start(1, 1, wait=False) gevent.sleep(short_time / 2) runner.quit() > self.assertEqual("first", MyTaskSet.state) E AssertionError: 'first' != 'third' E - first E + third locust/test/test_runners.py:3944: AssertionError ------------------------------ Captured log call ------------------------------- INFO locust.runners:runners.py:499 Ramping to 1 users at a rate of 1.00 per second INFO locust.runners:runners.py:537 All users spawned: {"MyTestUser": 1} (1 total users) ______________ TestStopTimeout.test_stop_timeout_during_on_start _______________ self = def test_stop_timeout_during_on_start(self): short_time = 0.05 class MyTaskSet(TaskSet): finished_on_start = False my_task_run = False def on_start(self): gevent.sleep(short_time) MyTaskSet.finished_on_start = True @task def my_task(self): MyTaskSet.my_task_run = True class MyTestUser(User): tasks = [MyTaskSet] environment = create_environment([MyTestUser], mocked_options()) environment.stop_timeout = short_time runner = environment.create_local_runner() runner.start(1, 1) gevent.sleep(short_time / 2) runner.quit() self.assertTrue(MyTaskSet.finished_on_start) > self.assertFalse(MyTaskSet.my_task_run) E AssertionError: True is not false locust/test/test_runners.py:3996: AssertionError ------------------------------ Captured log call ------------------------------- INFO locust.runners:runners.py:499 Ramping to 1 users at a rate of 1.00 per second INFO locust.runners:runners.py:537 All users spawned: {"MyTestUser": 1} (1 total users) INFO locust.runners:runners.py:141 Resetting stats _______________________ TestCsvStats.test_stats_history ________________________ self = def test_stats_history(self): env1 = Environment(events=locust.events, catch_exceptions=False) runner1 = env1.create_master_runner("127.0.0.1", 5558) env2 = Environment(events=locust.events, catch_exceptions=False) > runner2 = env2.create_worker_runner("127.0.0.1", 5558) locust/test/test_stats.py:589: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ locust/env.py:153: in create_worker_runner return self._create_runner( locust/env.py:115: in _create_runner self.runner = runner_class(self, *args, **kwargs) locust/runners.py:1216: in __init__ self.connect_to_master() locust/runners.py:1445: in connect_to_master self.connect_to_master() locust/runners.py:1445: in connect_to_master self.connect_to_master() locust/runners.py:1445: in connect_to_master self.connect_to_master() locust/runners.py:1445: in connect_to_master self.connect_to_master() locust/runners.py:1445: in connect_to_master self.connect_to_master() locust/runners.py:1445: in connect_to_master self.connect_to_master() locust/runners.py:1445: in connect_to_master self.connect_to_master() locust/runners.py:1445: in connect_to_master self.connect_to_master() locust/runners.py:1445: in connect_to_master self.connect_to_master() locust/runners.py:1445: in connect_to_master self.connect_to_master() locust/runners.py:1445: in connect_to_master self.connect_to_master() locust/runners.py:1445: in connect_to_master self.connect_to_master() locust/runners.py:1445: in connect_to_master self.connect_to_master() locust/runners.py:1445: in connect_to_master self.connect_to_master() locust/runners.py:1445: in connect_to_master self.connect_to_master() locust/runners.py:1445: in connect_to_master self.connect_to_master() locust/runners.py:1445: in connect_to_master self.connect_to_master() locust/runners.py:1445: in connect_to_master self.connect_to_master() locust/runners.py:1445: in connect_to_master self.connect_to_master() locust/runners.py:1445: in connect_to_master self.connect_to_master() locust/runners.py:1445: in connect_to_master self.connect_to_master() locust/runners.py:1445: in connect_to_master self.connect_to_master() locust/runners.py:1445: in connect_to_master self.connect_to_master() locust/runners.py:1445: in connect_to_master self.connect_to_master() locust/runners.py:1445: in connect_to_master self.connect_to_master() locust/runners.py:1445: in connect_to_master self.connect_to_master() locust/runners.py:1445: in connect_to_master self.connect_to_master() locust/runners.py:1445: in connect_to_master self.connect_to_master() locust/runners.py:1445: in connect_to_master self.connect_to_master() locust/runners.py:1445: in connect_to_master self.connect_to_master() locust/runners.py:1445: in connect_to_master self.connect_to_master() locust/runners.py:1445: in connect_to_master self.connect_to_master() locust/runners.py:1445: in connect_to_master self.connect_to_master() locust/runners.py:1445: in connect_to_master self.connect_to_master() locust/runners.py:1445: in connect_to_master self.connect_to_master() locust/runners.py:1445: in connect_to_master self.connect_to_master() locust/runners.py:1445: in connect_to_master self.connect_to_master() locust/runners.py:1445: in connect_to_master self.connect_to_master() locust/runners.py:1445: in connect_to_master self.connect_to_master() locust/runners.py:1445: in connect_to_master self.connect_to_master() locust/runners.py:1445: in connect_to_master self.connect_to_master() locust/runners.py:1445: in connect_to_master self.connect_to_master() locust/runners.py:1445: in connect_to_master self.connect_to_master() locust/runners.py:1445: in connect_to_master self.connect_to_master() locust/runners.py:1445: in connect_to_master self.connect_to_master() locust/runners.py:1445: in connect_to_master self.connect_to_master() locust/runners.py:1445: in connect_to_master self.connect_to_master() locust/runners.py:1445: in connect_to_master self.connect_to_master() locust/runners.py:1445: in connect_to_master self.connect_to_master() locust/runners.py:1445: in connect_to_master self.connect_to_master() locust/runners.py:1445: in connect_to_master self.connect_to_master() locust/runners.py:1445: in connect_to_master self.connect_to_master() locust/runners.py:1445: in connect_to_master self.connect_to_master() locust/runners.py:1445: in connect_to_master self.connect_to_master() locust/runners.py:1445: in connect_to_master self.connect_to_master() locust/runners.py:1445: in connect_to_master self.connect_to_master() locust/runners.py:1445: in connect_to_master self.connect_to_master() locust/runners.py:1445: in connect_to_master self.connect_to_master() locust/runners.py:1445: in connect_to_master self.connect_to_master() locust/runners.py:1445: in connect_to_master self.connect_to_master() _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = def connect_to_master(self): self.retry += 1 self.client.send(Message("client_ready", __version__, self.client_id)) try: success = self.connection_event.wait(timeout=CONNECT_TIMEOUT) except KeyboardInterrupt: # dont complain about getting CTRL-C sys.exit(1) if not success: if self.retry < 3: logger.debug( f"Failed to connect to master {self.master_host}:{self.master_port}, retry {self.retry}/{CONNECT_RETRY_COUNT}." ) else: logger.warning( f"Failed to connect to master {self.master_host}:{self.master_port}, retry {self.retry}/{CONNECT_RETRY_COUNT}." ) if self.retry > CONNECT_RETRY_COUNT: > raise ConnectionError() E ConnectionError locust/runners.py:1444: ConnectionError ------------------------------ Captured log call ------------------------------- ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (i-capture-the-hostname_891baf3759bf47ad8d689b2b93b5acfe). That's not going to work. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (i-capture-the-hostname_891baf3759bf47ad8d689b2b93b5acfe). That's not going to work. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (i-capture-the-hostname_891baf3759bf47ad8d689b2b93b5acfe). That's not going to work. WARNING locust.runners:runners.py:1440 Failed to connect to master 127.0.0.1:5558, retry 3/60. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (i-capture-the-hostname_891baf3759bf47ad8d689b2b93b5acfe). That's not going to work. WARNING locust.runners:runners.py:1440 Failed to connect to master 127.0.0.1:5558, retry 4/60. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (i-capture-the-hostname_891baf3759bf47ad8d689b2b93b5acfe). That's not going to work. WARNING locust.runners:runners.py:1440 Failed to connect to master 127.0.0.1:5558, retry 5/60. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (i-capture-the-hostname_891baf3759bf47ad8d689b2b93b5acfe). That's not going to work. WARNING locust.runners:runners.py:1440 Failed to connect to master 127.0.0.1:5558, retry 6/60. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (i-capture-the-hostname_891baf3759bf47ad8d689b2b93b5acfe). That's not going to work. WARNING locust.runners:runners.py:1440 Failed to connect to master 127.0.0.1:5558, retry 7/60. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (i-capture-the-hostname_891baf3759bf47ad8d689b2b93b5acfe). That's not going to work. WARNING locust.runners:runners.py:1440 Failed to connect to master 127.0.0.1:5558, retry 8/60. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (i-capture-the-hostname_891baf3759bf47ad8d689b2b93b5acfe). That's not going to work. WARNING locust.runners:runners.py:1440 Failed to connect to master 127.0.0.1:5558, retry 9/60. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (i-capture-the-hostname_891baf3759bf47ad8d689b2b93b5acfe). That's not going to work. WARNING locust.runners:runners.py:1440 Failed to connect to master 127.0.0.1:5558, retry 10/60. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (i-capture-the-hostname_891baf3759bf47ad8d689b2b93b5acfe). That's not going to work. WARNING locust.runners:runners.py:1440 Failed to connect to master 127.0.0.1:5558, retry 11/60. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (i-capture-the-hostname_891baf3759bf47ad8d689b2b93b5acfe). That's not going to work. WARNING locust.runners:runners.py:1440 Failed to connect to master 127.0.0.1:5558, retry 12/60. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (i-capture-the-hostname_891baf3759bf47ad8d689b2b93b5acfe). That's not going to work. WARNING locust.runners:runners.py:1440 Failed to connect to master 127.0.0.1:5558, retry 13/60. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (i-capture-the-hostname_891baf3759bf47ad8d689b2b93b5acfe). That's not going to work. WARNING locust.runners:runners.py:1440 Failed to connect to master 127.0.0.1:5558, retry 14/60. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (i-capture-the-hostname_891baf3759bf47ad8d689b2b93b5acfe). That's not going to work. WARNING locust.runners:runners.py:1440 Failed to connect to master 127.0.0.1:5558, retry 15/60. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (i-capture-the-hostname_891baf3759bf47ad8d689b2b93b5acfe). That's not going to work. WARNING locust.runners:runners.py:1440 Failed to connect to master 127.0.0.1:5558, retry 16/60. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (i-capture-the-hostname_891baf3759bf47ad8d689b2b93b5acfe). That's not going to work. WARNING locust.runners:runners.py:1440 Failed to connect to master 127.0.0.1:5558, retry 17/60. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (i-capture-the-hostname_891baf3759bf47ad8d689b2b93b5acfe). That's not going to work. WARNING locust.runners:runners.py:1440 Failed to connect to master 127.0.0.1:5558, retry 18/60. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (i-capture-the-hostname_891baf3759bf47ad8d689b2b93b5acfe). That's not going to work. WARNING locust.runners:runners.py:1440 Failed to connect to master 127.0.0.1:5558, retry 19/60. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (i-capture-the-hostname_891baf3759bf47ad8d689b2b93b5acfe). That's not going to work. WARNING locust.runners:runners.py:1440 Failed to connect to master 127.0.0.1:5558, retry 20/60. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (i-capture-the-hostname_891baf3759bf47ad8d689b2b93b5acfe). That's not going to work. WARNING locust.runners:runners.py:1440 Failed to connect to master 127.0.0.1:5558, retry 21/60. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (i-capture-the-hostname_891baf3759bf47ad8d689b2b93b5acfe). That's not going to work. WARNING locust.runners:runners.py:1440 Failed to connect to master 127.0.0.1:5558, retry 22/60. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (i-capture-the-hostname_891baf3759bf47ad8d689b2b93b5acfe). That's not going to work. WARNING locust.runners:runners.py:1440 Failed to connect to master 127.0.0.1:5558, retry 23/60. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (i-capture-the-hostname_891baf3759bf47ad8d689b2b93b5acfe). That's not going to work. WARNING locust.runners:runners.py:1440 Failed to connect to master 127.0.0.1:5558, retry 24/60. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (i-capture-the-hostname_891baf3759bf47ad8d689b2b93b5acfe). That's not going to work. WARNING locust.runners:runners.py:1440 Failed to connect to master 127.0.0.1:5558, retry 25/60. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (i-capture-the-hostname_891baf3759bf47ad8d689b2b93b5acfe). That's not going to work. WARNING locust.runners:runners.py:1440 Failed to connect to master 127.0.0.1:5558, retry 26/60. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (i-capture-the-hostname_891baf3759bf47ad8d689b2b93b5acfe). That's not going to work. WARNING locust.runners:runners.py:1440 Failed to connect to master 127.0.0.1:5558, retry 27/60. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (i-capture-the-hostname_891baf3759bf47ad8d689b2b93b5acfe). That's not going to work. WARNING locust.runners:runners.py:1440 Failed to connect to master 127.0.0.1:5558, retry 28/60. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (i-capture-the-hostname_891baf3759bf47ad8d689b2b93b5acfe). That's not going to work. WARNING locust.runners:runners.py:1440 Failed to connect to master 127.0.0.1:5558, retry 29/60. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (i-capture-the-hostname_891baf3759bf47ad8d689b2b93b5acfe). That's not going to work. WARNING locust.runners:runners.py:1440 Failed to connect to master 127.0.0.1:5558, retry 30/60. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (i-capture-the-hostname_891baf3759bf47ad8d689b2b93b5acfe). That's not going to work. WARNING locust.runners:runners.py:1440 Failed to connect to master 127.0.0.1:5558, retry 31/60. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (i-capture-the-hostname_891baf3759bf47ad8d689b2b93b5acfe). That's not going to work. WARNING locust.runners:runners.py:1440 Failed to connect to master 127.0.0.1:5558, retry 32/60. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (i-capture-the-hostname_891baf3759bf47ad8d689b2b93b5acfe). That's not going to work. WARNING locust.runners:runners.py:1440 Failed to connect to master 127.0.0.1:5558, retry 33/60. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (i-capture-the-hostname_891baf3759bf47ad8d689b2b93b5acfe). That's not going to work. WARNING locust.runners:runners.py:1440 Failed to connect to master 127.0.0.1:5558, retry 34/60. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (i-capture-the-hostname_891baf3759bf47ad8d689b2b93b5acfe). That's not going to work. WARNING locust.runners:runners.py:1440 Failed to connect to master 127.0.0.1:5558, retry 35/60. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (i-capture-the-hostname_891baf3759bf47ad8d689b2b93b5acfe). That's not going to work. WARNING locust.runners:runners.py:1440 Failed to connect to master 127.0.0.1:5558, retry 36/60. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (i-capture-the-hostname_891baf3759bf47ad8d689b2b93b5acfe). That's not going to work. WARNING locust.runners:runners.py:1440 Failed to connect to master 127.0.0.1:5558, retry 37/60. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (i-capture-the-hostname_891baf3759bf47ad8d689b2b93b5acfe). That's not going to work. WARNING locust.runners:runners.py:1440 Failed to connect to master 127.0.0.1:5558, retry 38/60. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (i-capture-the-hostname_891baf3759bf47ad8d689b2b93b5acfe). That's not going to work. WARNING locust.runners:runners.py:1440 Failed to connect to master 127.0.0.1:5558, retry 39/60. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (i-capture-the-hostname_891baf3759bf47ad8d689b2b93b5acfe). That's not going to work. WARNING locust.runners:runners.py:1440 Failed to connect to master 127.0.0.1:5558, retry 40/60. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (i-capture-the-hostname_891baf3759bf47ad8d689b2b93b5acfe). That's not going to work. WARNING locust.runners:runners.py:1440 Failed to connect to master 127.0.0.1:5558, retry 41/60. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (i-capture-the-hostname_891baf3759bf47ad8d689b2b93b5acfe). That's not going to work. WARNING locust.runners:runners.py:1440 Failed to connect to master 127.0.0.1:5558, retry 42/60. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (i-capture-the-hostname_891baf3759bf47ad8d689b2b93b5acfe). That's not going to work. WARNING locust.runners:runners.py:1440 Failed to connect to master 127.0.0.1:5558, retry 43/60. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (i-capture-the-hostname_891baf3759bf47ad8d689b2b93b5acfe). That's not going to work. WARNING locust.runners:runners.py:1440 Failed to connect to master 127.0.0.1:5558, retry 44/60. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (i-capture-the-hostname_891baf3759bf47ad8d689b2b93b5acfe). That's not going to work. WARNING locust.runners:runners.py:1440 Failed to connect to master 127.0.0.1:5558, retry 45/60. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (i-capture-the-hostname_891baf3759bf47ad8d689b2b93b5acfe). That's not going to work. WARNING locust.runners:runners.py:1440 Failed to connect to master 127.0.0.1:5558, retry 46/60. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (i-capture-the-hostname_891baf3759bf47ad8d689b2b93b5acfe). That's not going to work. WARNING locust.runners:runners.py:1440 Failed to connect to master 127.0.0.1:5558, retry 47/60. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (i-capture-the-hostname_891baf3759bf47ad8d689b2b93b5acfe). That's not going to work. WARNING locust.runners:runners.py:1440 Failed to connect to master 127.0.0.1:5558, retry 48/60. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (i-capture-the-hostname_891baf3759bf47ad8d689b2b93b5acfe). That's not going to work. WARNING locust.runners:runners.py:1440 Failed to connect to master 127.0.0.1:5558, retry 49/60. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (i-capture-the-hostname_891baf3759bf47ad8d689b2b93b5acfe). That's not going to work. WARNING locust.runners:runners.py:1440 Failed to connect to master 127.0.0.1:5558, retry 50/60. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (i-capture-the-hostname_891baf3759bf47ad8d689b2b93b5acfe). That's not going to work. WARNING locust.runners:runners.py:1440 Failed to connect to master 127.0.0.1:5558, retry 51/60. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (i-capture-the-hostname_891baf3759bf47ad8d689b2b93b5acfe). That's not going to work. WARNING locust.runners:runners.py:1440 Failed to connect to master 127.0.0.1:5558, retry 52/60. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (i-capture-the-hostname_891baf3759bf47ad8d689b2b93b5acfe). That's not going to work. WARNING locust.runners:runners.py:1440 Failed to connect to master 127.0.0.1:5558, retry 53/60. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (i-capture-the-hostname_891baf3759bf47ad8d689b2b93b5acfe). That's not going to work. WARNING locust.runners:runners.py:1440 Failed to connect to master 127.0.0.1:5558, retry 54/60. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (i-capture-the-hostname_891baf3759bf47ad8d689b2b93b5acfe). That's not going to work. WARNING locust.runners:runners.py:1440 Failed to connect to master 127.0.0.1:5558, retry 55/60. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (i-capture-the-hostname_891baf3759bf47ad8d689b2b93b5acfe). That's not going to work. WARNING locust.runners:runners.py:1440 Failed to connect to master 127.0.0.1:5558, retry 56/60. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (i-capture-the-hostname_891baf3759bf47ad8d689b2b93b5acfe). That's not going to work. WARNING locust.runners:runners.py:1440 Failed to connect to master 127.0.0.1:5558, retry 57/60. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (i-capture-the-hostname_891baf3759bf47ad8d689b2b93b5acfe). That's not going to work. WARNING locust.runners:runners.py:1440 Failed to connect to master 127.0.0.1:5558, retry 58/60. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (i-capture-the-hostname_891baf3759bf47ad8d689b2b93b5acfe). That's not going to work. WARNING locust.runners:runners.py:1440 Failed to connect to master 127.0.0.1:5558, retry 59/60. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (i-capture-the-hostname_891baf3759bf47ad8d689b2b93b5acfe). That's not going to work. WARNING locust.runners:runners.py:1440 Failed to connect to master 127.0.0.1:5558, retry 60/60. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (i-capture-the-hostname_891baf3759bf47ad8d689b2b93b5acfe). That's not going to work. WARNING locust.runners:runners.py:1440 Failed to connect to master 127.0.0.1:5558, retry 61/60. ______________ TestCsvStats.test_user_count_in_csv_history_stats _______________ self = @mock.patch("locust.stats.CSV_STATS_INTERVAL_SEC", new=_TEST_CSV_STATS_INTERVAL_SEC) def test_user_count_in_csv_history_stats(self): start_time = int(time.time()) class TestUser(User): wait_time = constant(10) @task def t(self): self.environment.runner.stats.log_request("GET", "/", 10, 10) environment = Environment(user_classes=[TestUser]) stats_writer = StatsCSVFileWriter(environment, PERCENTILES_TO_REPORT, self.STATS_BASE_NAME, full_history=True) runner = environment.create_local_runner() # spawn a user every _TEST_CSV_STATS_INTERVAL_SEC second user_count = 15 spawn_rate = 5 assert 1 / 5 == _TEST_CSV_STATS_INTERVAL_SEC runner_greenlet = gevent.spawn(runner.start, user_count, spawn_rate) gevent.sleep(0.1) greenlet = gevent.spawn(stats_writer) gevent.sleep(user_count / spawn_rate) gevent.kill(greenlet) stats_writer.close_files() runner.stop() gevent.kill(runner_greenlet) with open(self.STATS_HISTORY_FILENAME) as f: reader = csv.DictReader(f) rows = [r for r in reader] > self.assertEqual(2 * user_count, len(rows)) E AssertionError: 30 != 26 locust/test/test_stats.py:545: AssertionError ------------------------------ Captured log call ------------------------------- INFO locust.runners:runners.py:499 Ramping to 15 users at a rate of 5.00 per second INFO locust.runners:runners.py:537 All users spawned: {"TestUser": 15} (15 total users) ____________________ TestWaitTime.test_constant_throughput _____________________ self = def test_constant_throughput(self): class MyUser(User): wait_time = constant_throughput(10) class TS(TaskSet): pass ts = TS(MyUser(self.environment)) ts2 = TS(MyUser(self.environment)) previous_time = time.perf_counter() for i in range(7): ts.wait() since_last_run = time.perf_counter() - previous_time > self.assertLess(abs(0.1 - since_last_run), 0.02) E AssertionError: 0.03398058099846821 not less than 0.02 locust/test/test_wait_time.py:75: AssertionError =============================== warnings summary =============================== locust/test/test_fasthttp.py::TestFastHttpSsl::test_ssl_request_insecure locust/test/test_web.py::TestWebUIWithTLS::test_index_with_https /usr/lib/python3/dist-packages/gevent/ssl.py:237: DeprecationWarning: ssl.PROTOCOL_TLS is deprecated self._context = SSLContext(ssl_version) -- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html =========================== short test summary info ============================ FAILED locust/test/test_http.py::TestHttpSession::test_event_measure - Assert... FAILED locust/test/test_load_locustfile.py::TestLoadLocustfile::test_locustfile_from_url FAILED locust/test/test_log.py::TestLoggingOptions::test_log_to_file - OSErro... FAILED locust/test/test_log.py::TestLoggingOptions::test_logging_output - OSE... FAILED locust/test/test_log.py::TestLoggingOptions::test_skip_logging - OSErr... FAILED locust/test/test_log.py::TestLoggingOptions::test_user_broken_on_start FAILED locust/test/test_main.py::StandaloneIntegrationTests::test_autostart_multiple_locustfiles_with_shape FAILED locust/test/test_main.py::StandaloneIntegrationTests::test_autostart_w_load_shape FAILED locust/test/test_main.py::StandaloneIntegrationTests::test_autostart_w_run_time FAILED locust/test/test_main.py::StandaloneIntegrationTests::test_autostart_wo_run_time FAILED locust/test/test_main.py::StandaloneIntegrationTests::test_command_line_user_selection FAILED locust/test/test_main.py::StandaloneIntegrationTests::test_custom_arguments FAILED locust/test/test_main.py::StandaloneIntegrationTests::test_custom_arguments_in_file FAILED locust/test/test_main.py::StandaloneIntegrationTests::test_custom_exit_code FAILED locust/test/test_main.py::StandaloneIntegrationTests::test_default_headless_spawn_options FAILED locust/test/test_main.py::StandaloneIntegrationTests::test_default_headless_spawn_options_with_shape FAILED locust/test/test_main.py::StandaloneIntegrationTests::test_error_when_duplicate_shape_class_names FAILED locust/test/test_main.py::StandaloneIntegrationTests::test_error_when_duplicate_userclass_names FAILED locust/test/test_main.py::StandaloneIntegrationTests::test_error_when_locustfiles_directory_is_empty FAILED locust/test/test_main.py::StandaloneIntegrationTests::test_error_when_no_tasks_match_tags FAILED locust/test/test_main.py::StandaloneIntegrationTests::test_error_when_providing_both_run_time_and_a_shape_class FAILED locust/test/test_main.py::StandaloneIntegrationTests::test_graceful_exit_when_keyboard_interrupt FAILED locust/test/test_main.py::StandaloneIntegrationTests::test_headless_spawn_options_wo_run_time FAILED locust/test/test_main.py::StandaloneIntegrationTests::test_help_arg - ... FAILED locust/test/test_main.py::StandaloneIntegrationTests::test_html_report_option FAILED locust/test/test_main.py::StandaloneIntegrationTests::test_input - Ass... FAILED locust/test/test_main.py::StandaloneIntegrationTests::test_invalid_percentile_parameter FAILED locust/test/test_main.py::StandaloneIntegrationTests::test_invalid_stop_timeout_string FAILED locust/test/test_main.py::StandaloneIntegrationTests::test_no_error_when_same_userclass_in_two_files FAILED locust/test/test_main.py::StandaloneIntegrationTests::test_percentile_parameter FAILED locust/test/test_main.py::StandaloneIntegrationTests::test_percentiles_to_statistics FAILED locust/test/test_main.py::StandaloneIntegrationTests::test_run_autostart_with_multiple_locustfiles FAILED locust/test/test_main.py::StandaloneIntegrationTests::test_run_headless_with_multiple_locustfiles FAILED locust/test/test_main.py::StandaloneIntegrationTests::test_run_headless_with_multiple_locustfiles_with_shape FAILED locust/test/test_main.py::StandaloneIntegrationTests::test_run_with_userclass_picker FAILED locust/test/test_main.py::StandaloneIntegrationTests::test_shape_class_log_disabled_parameters FAILED locust/test/test_main.py::StandaloneIntegrationTests::test_shape_class_with_use_common_options FAILED locust/test/test_main.py::StandaloneIntegrationTests::test_spawing_with_fixed_multiple_locustfiles FAILED locust/test/test_main.py::StandaloneIntegrationTests::test_spawning_with_fixed FAILED locust/test/test_main.py::StandaloneIntegrationTests::test_web_options FAILED locust/test/test_main.py::StandaloneIntegrationTests::test_webserver FAILED locust/test/test_main.py::StandaloneIntegrationTests::test_webserver_multiple_locustfiles FAILED locust/test/test_main.py::StandaloneIntegrationTests::test_webserver_multiple_locustfiles_in_directory FAILED locust/test/test_main.py::StandaloneIntegrationTests::test_webserver_multiple_locustfiles_with_shape FAILED locust/test/test_main.py::DistributedIntegrationTests::test_distributed FAILED locust/test/test_main.py::DistributedIntegrationTests::test_distributed_events FAILED locust/test/test_main.py::DistributedIntegrationTests::test_distributed_report_timeout_expired FAILED locust/test/test_main.py::DistributedIntegrationTests::test_distributed_tags FAILED locust/test/test_main.py::DistributedIntegrationTests::test_distributed_with_locustfile_distribution_not_plain_filename FAILED locust/test/test_main.py::DistributedIntegrationTests::test_expect_workers FAILED locust/test/test_main.py::DistributedIntegrationTests::test_json_schema FAILED locust/test/test_main.py::DistributedIntegrationTests::test_locustfile_distribution FAILED locust/test/test_main.py::DistributedIntegrationTests::test_locustfile_distribution_with_workers_started_first FAILED locust/test/test_main.py::DistributedIntegrationTests::test_processes FAILED locust/test/test_main.py::DistributedIntegrationTests::test_processes_autodetect FAILED locust/test/test_main.py::DistributedIntegrationTests::test_processes_ctrl_c FAILED locust/test/test_main.py::DistributedIntegrationTests::test_processes_error_doesnt_blow_up_completely FAILED locust/test/test_main.py::DistributedIntegrationTests::test_processes_separate_worker FAILED locust/test/test_main.py::DistributedIntegrationTests::test_processes_workers_quit_unexpected FAILED locust/test/test_main.py::DistributedIntegrationTests::test_worker_indexes FAILED locust/test/test_main.py::DistributedIntegrationTests::test_workers_shut_down_if_master_is_gone FAILED locust/test/test_runners.py::TestLocustRunner::test_cpu_warning - Asse... FAILED locust/test/test_runners.py::TestLocustRunner::test_stop_users_with_spawn_rate FAILED locust/test/test_runners.py::TestMasterRunner::test_attributes_populated_when_calling_start FAILED locust/test/test_runners.py::TestMasterRunner::test_custom_shape_scale_down FAILED locust/test/test_runners.py::TestMasterRunner::test_custom_shape_scale_interval FAILED locust/test/test_runners.py::TestMasterRunner::test_custom_shape_scale_up FAILED locust/test/test_runners.py::TestMasterRunner::test_last_worker_missing_stops_test FAILED locust/test/test_runners.py::TestMasterRunner::test_last_worker_quitting_stops_test FAILED locust/test/test_runners.py::TestMasterRunner::test_master_discard_first_client_ready FAILED locust/test/test_runners.py::TestMasterRunner::test_master_marks_downed_workers_as_missing FAILED locust/test/test_runners.py::TestMasterRunner::test_master_reset_connection FAILED locust/test/test_runners.py::TestMasterRunner::test_rebalance_locust_users_on_worker_connect FAILED locust/test/test_runners.py::TestMasterRunner::test_reset_connection_after_RPCError FAILED locust/test/test_runners.py::TestMasterRunner::test_spawn_correct_worker_indexes FAILED locust/test/test_runners.py::TestMasterRunner::test_spawn_fewer_locusts_than_workers FAILED locust/test/test_runners.py::TestMasterRunner::test_spawn_uneven_locusts FAILED locust/test/test_runners.py::TestMasterRunner::test_start_event - Asse... FAILED locust/test/test_runners.py::TestMasterRunner::test_stop_event - Asser... FAILED locust/test/test_runners.py::TestMasterRunner::test_stop_event_quit - ... FAILED locust/test/test_runners.py::TestMasterRunner::test_unknown_host_sends_message_to_master FAILED locust/test/test_runners.py::TestMasterRunner::test_worker_connect - A... FAILED locust/test/test_runners.py::TestMasterRunner::test_worker_connect_with_special_versions FAILED locust/test/test_runners.py::TestMasterRunner::test_worker_missing_after_heartbeat_dead_interval FAILED locust/test/test_runners.py::TestMasterRunner::test_worker_sends_bad_message_to_master FAILED locust/test/test_runners.py::TestMasterRunner::test_worker_sends_unrecognized_message_to_master FAILED locust/test/test_runners.py::TestStopTimeout::test_kill_locusts_with_stop_timeout FAILED locust/test/test_runners.py::TestStopTimeout::test_stop_timeout - Asse... FAILED locust/test/test_runners.py::TestStopTimeout::test_stop_timeout_during_on_start FAILED locust/test/test_stats.py::TestCsvStats::test_stats_history - Connecti... FAILED locust/test/test_stats.py::TestCsvStats::test_user_count_in_csv_history_stats FAILED locust/test/test_wait_time.py::TestWaitTime::test_constant_throughput = 92 failed, 456 passed, 1 skipped, 15 deselected, 2 warnings in 582.31s (0:09:42) = E: pybuild pybuild:389: test: plugin custom failed with: exit code=1: PYTHONPATH=/build/reproducible-path/locust-2.24.0/.pybuild/cpython3_3.11_locust/build python3.11 -m pytest -v --ignore=examples/test_data_management.py -k 'not TestMasterWorkerRunners' dh_auto_test: error: pybuild --test --test-pytest -i python{version} -p "3.12 3.11" returned exit code 13 make[1]: [debian/rules:15: override_dh_auto_test] Error 25 (ignored) make[1]: Leaving directory '/build/reproducible-path/locust-2.24.0' create-stamp debian/debhelper-build-stamp fakeroot debian/rules binary dh binary --with python3 --buildsystem=pybuild dh_testroot -O--buildsystem=pybuild dh_prep -O--buildsystem=pybuild dh_auto_install --destdir=debian/python3-locust/ -O--buildsystem=pybuild I: pybuild plugin_pyproject:178: Copying package built for python3.12 to destdir I: pybuild plugin_pyproject:178: Copying package built for python3.11 to destdir dh_installdocs -O--buildsystem=pybuild dh_installchangelogs -O--buildsystem=pybuild debian/rules override_dh_installexamples make[1]: Entering directory '/build/reproducible-path/locust-2.24.0' dh_installexamples -X.pyc make[1]: Leaving directory '/build/reproducible-path/locust-2.24.0' dh_python3 -O--buildsystem=pybuild dh_installsystemduser -O--buildsystem=pybuild dh_perl -O--buildsystem=pybuild dh_link -O--buildsystem=pybuild dh_strip_nondeterminism -O--buildsystem=pybuild dh_compress -O--buildsystem=pybuild dh_fixperms -O--buildsystem=pybuild dh_missing -O--buildsystem=pybuild dh_installdeb -O--buildsystem=pybuild dh_gencontrol -O--buildsystem=pybuild dpkg-gencontrol: warning: Recommends field of package python3-locust: substitution variable ${python3:Recommends} used, but is not defined dpkg-gencontrol: warning: Suggests field of package python3-locust: substitution variable ${python3:Suggests} used, but is not defined dh_md5sums -O--buildsystem=pybuild dh_builddeb -O--buildsystem=pybuild dpkg-deb: building package 'python3-locust' in '../python3-locust_2.24.0-1_all.deb'. dpkg-genbuildinfo --build=binary -O../locust_2.24.0-1_arm64.buildinfo dpkg-genchanges --build=binary -O../locust_2.24.0-1_arm64.changes dpkg-genchanges: info: binary-only upload (no source code included) dpkg-source --after-build . dpkg-source: info: using options from locust-2.24.0/debian/source/options: --extend-diff-ignore=^[^/]+.egg-info/ dpkg-buildpackage: info: binary-only upload (no source included) dpkg-genchanges: info: including full source code in upload I: copying local configuration I: user script /srv/workspace/pbuilder/227080/tmp/hooks/B01_cleanup starting I: user script /srv/workspace/pbuilder/227080/tmp/hooks/B01_cleanup finished I: unmounting dev/ptmx filesystem I: unmounting dev/pts filesystem I: unmounting dev/shm filesystem I: unmounting proc filesystem I: unmounting sys filesystem I: cleaning the build env I: removing directory /srv/workspace/pbuilder/227080 and its subdirectories I: Current time: Fri May 10 02:14:52 +14 2024 I: pbuilder-time-stamp: 1715256892