Thu May 9 02:36:39 UTC 2024 I: starting to build locust/trixie/armhf on jenkins on '2024-05-09 02:36' Thu May 9 02:36:39 UTC 2024 I: The jenkins build log is/was available at https://jenkins.debian.net/userContent/reproducible/debian/build_service/armhf_16/5486/console.log Thu May 9 02:36:39 UTC 2024 I: Downloading source for trixie/locust=2.24.0-1 --2024-05-09 02:36:39-- http://deb.debian.org/debian/pool/main/l/locust/locust_2.24.0-1.dsc Connecting to 46.16.76.132:3128... connected. Proxy request sent, awaiting response... 200 OK Length: 2388 (2.3K) [text/prs.lines.tag] Saving to: ‘locust_2.24.0-1.dsc’ 0K .. 100% 320M=0s 2024-05-09 02:36:39 (320 MB/s) - ‘locust_2.24.0-1.dsc’ saved [2388/2388] Thu May 9 02:36:39 UTC 2024 I: locust_2.24.0-1.dsc -----BEGIN PGP SIGNED MESSAGE----- Hash: SHA256 Format: 3.0 (quilt) Source: locust Binary: python3-locust Architecture: all Version: 2.24.0-1 Maintainer: Sandro Tosi Homepage: https://locust.io/ Standards-Version: 4.6.2.0 Vcs-Browser: https://salsa.debian.org/morph/locust Vcs-Git: https://salsa.debian.org/morph/locust.git Build-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) Package-List: python3-locust deb python optional arch=all Checksums-Sha1: 40d88b864ac9598d59a9c1690098634cb4111921 1661668 locust_2.24.0.orig.tar.xz 8409da5c973155eb9fda8e5fc1bf5b3f07591368 333540 locust_2.24.0-1.debian.tar.xz Checksums-Sha256: e5a2ed3998bb59cbb639e8f0c9523ae093fedc92670fc80d93b11f0cbbfb7cc6 1661668 locust_2.24.0.orig.tar.xz e2cb7412a26f081e366f40c21f7ac1b000b63f4cc977aa9c983aabcc3e9588aa 333540 locust_2.24.0-1.debian.tar.xz Files: fa97f526df990e592546c6f94d16f92f 1661668 locust_2.24.0.orig.tar.xz c75c25dc66bbe70dca3f93c64d01d2d8 333540 locust_2.24.0-1.debian.tar.xz -----BEGIN PGP SIGNATURE----- iQIzBAEBCAAdFiEEufrTGSrz5KUwnZ05h588mTgBqU8FAmXxLqcACgkQh588mTgB qU9l1Q//UobeGUveeGALV6fQJfT4UdUUsAN/HyhiCZmgW5UoNxublTBbR3htV+GW xsIZaED648mBpBl2fBkPg9wQDs2uJFdpLWtDtQKPF7btgtF/lzoJm1osaF2raoJ7 d+TNOIB3C03D8pgSvBdDmpcUi3TYebegD+o8PcwovEb4er5/png2Ib5TL9BPcBkv pgOrLj/AR+HC13l43rlw9TPt9hS4Xl6nqA+mefYElZh9BRMTDP6fv3axKw3/XCUN fEHX/MPGfjSeRInxAj3eMZwER7YXxwUNNkss/Vt5U0kiarHiIskUOBBKyPDJJXOb 31tkEu8sVisPrBy5D0eJi9Yn/nm6dOLfSABJvHNMB3SBBnlEjaV3Vbxh7u/XKrMS wIOx1RhK7ZZSJCjxFXR/qxNOCqCpzGwGslr1IAGctt9L4TPyw7TeNTLBHTOFoS8q 3a8IHKQcHJKqGSq3btGSLVc1lNynAUbg11zwUkXPJzUl39vp9ZbZ018jQCJmSQWY 3fYavYCDnkxBrVBEPnFu2ywqOP6PPr++s5r5WsGvRAJG86DDlUcedtrSX0aixVEN ZzjoxUih9VwqrOOhM6D644MMIwZ5ZIeXXdoNaVH8l+wmpQ9ygkwEe9pDZ8jdopVh qPn3w7TEOJt/ZYEX0Yyb3Wp5i5V/NzZdIlekLKmon1qGUVPNQKI= =H/Fn -----END PGP SIGNATURE----- Thu May 9 02:36:39 UTC 2024 I: Checking whether the package is not for us Thu May 9 02:36:39 UTC 2024 I: Starting 1st build on remote node virt32b-armhf-rb.debian.net. Thu May 9 02:36:39 UTC 2024 I: Preparing to do remote build '1' on virt32b-armhf-rb.debian.net. Thu May 9 03:04:00 UTC 2024 I: Deleting $TMPDIR on virt32b-armhf-rb.debian.net. I: pbuilder: network access will be disabled during build I: Current time: Wed May 8 14:36:48 -12 2024 I: pbuilder-time-stamp: 1715222208 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/6492/tmp/hooks/D02_print_environment starting I: set BUILDDIR='/build/reproducible-path' BUILDUSERGECOS='first user,first room,first work-phone,first home-phone,first other' BUILDUSERNAME='pbuilder1' BUILD_ARCH='armhf' DEBIAN_FRONTEND='noninteractive' DEB_BUILD_OPTIONS='buildinfo=+all reproducible=+all parallel=3 ' DISTRIBUTION='trixie' HOME='/root' HOST_ARCH='armhf' IFS=' ' INVOCATION_ID='3388256fc1524f5dbbfc59189f7d47da' LANG='C' LANGUAGE='en_US:en' LC_ALL='C' MAIL='/var/mail/root' OPTIND='1' PATH='/usr/sbin:/usr/bin:/sbin:/bin:/usr/games' PBCURRENTCOMMANDLINEOPERATION='build' PBUILDER_OPERATION='build' PBUILDER_PKGDATADIR='/usr/share/pbuilder' PBUILDER_PKGLIBDIR='/usr/lib/pbuilder' PBUILDER_SYSCONFDIR='/etc' PPID='6492' PS1='# ' PS2='> ' PS4='+ ' PWD='/' SHELL='/bin/bash' SHLVL='2' SUDO_COMMAND='/usr/bin/timeout -k 18.1h 18h /usr/bin/ionice -c 3 /usr/bin/nice /usr/sbin/pbuilder --build --configfile /srv/reproducible-results/rbuild-debian/r-b-build.Jlc2lR3a/pbuilderrc_BNCF --distribution trixie --hookdir /etc/pbuilder/first-build-hooks --debbuildopts -b --basetgz /var/cache/pbuilder/trixie-reproducible-base.tgz --buildresult /srv/reproducible-results/rbuild-debian/r-b-build.Jlc2lR3a/b1 --logfile b1/build.log locust_2.24.0-1.dsc' SUDO_GID='112' SUDO_UID='106' SUDO_USER='jenkins' TERM='unknown' TZ='/usr/share/zoneinfo/Etc/GMT+12' USER='root' _='/usr/bin/systemd-run' http_proxy='http://10.0.0.15:3142/' I: uname -a Linux virt32b 6.1.0-21-armmp-lpae #1 SMP Debian 6.1.90-1 (2024-05-03) armv7l GNU/Linux I: ls -l /bin lrwxrwxrwx 1 root root 7 May 8 11:25 /bin -> usr/bin I: user script /srv/workspace/pbuilder/6492/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: armhf 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 ... 19444 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 45.3 MB of archives. After unpacking 168 MB will be used. Writing extended state information... Get: 1 http://deb.debian.org/debian trixie/main armhf fonts-lato all 2.015-1 [2780 kB] Get: 2 http://deb.debian.org/debian trixie/main armhf libpython3.11-minimal armhf 3.11.9-1 [805 kB] Get: 3 http://deb.debian.org/debian trixie/main armhf libexpat1 armhf 2.6.2-1 [83.5 kB] Get: 4 http://deb.debian.org/debian trixie/main armhf python3.11-minimal armhf 3.11.9-1 [1600 kB] Get: 5 http://deb.debian.org/debian trixie/main armhf python3-minimal armhf 3.11.8-1 [26.3 kB] Get: 6 http://deb.debian.org/debian trixie/main armhf media-types all 10.1.0 [26.9 kB] Get: 7 http://deb.debian.org/debian trixie/main armhf netbase all 6.4 [12.8 kB] Get: 8 http://deb.debian.org/debian trixie/main armhf tzdata all 2024a-4 [255 kB] Get: 9 http://deb.debian.org/debian trixie/main armhf readline-common all 8.2-4 [69.3 kB] Get: 10 http://deb.debian.org/debian trixie/main armhf libreadline8t64 armhf 8.2-4 [145 kB] Get: 11 http://deb.debian.org/debian trixie/main armhf libpython3.11-stdlib armhf 3.11.9-1 [1704 kB] Get: 12 http://deb.debian.org/debian trixie/main armhf python3.11 armhf 3.11.9-1 [602 kB] Get: 13 http://deb.debian.org/debian trixie/main armhf libpython3-stdlib armhf 3.11.8-1 [9332 B] Get: 14 http://deb.debian.org/debian trixie/main armhf python3 armhf 3.11.8-1 [27.4 kB] Get: 15 http://deb.debian.org/debian trixie/main armhf libpython3.12-minimal armhf 3.12.3-1 [795 kB] Get: 16 http://deb.debian.org/debian trixie/main armhf python3.12-minimal armhf 3.12.3-1 [1783 kB] Get: 17 http://deb.debian.org/debian trixie/main armhf sensible-utils all 0.0.22 [22.4 kB] Get: 18 http://deb.debian.org/debian trixie/main armhf openssl armhf 3.2.1-3 [1326 kB] Get: 19 http://deb.debian.org/debian trixie/main armhf ca-certificates all 20240203 [158 kB] Get: 20 http://deb.debian.org/debian trixie/main armhf libmagic-mgc armhf 1:5.45-3 [314 kB] Get: 21 http://deb.debian.org/debian trixie/main armhf libmagic1t64 armhf 1:5.45-3 [98.1 kB] Get: 22 http://deb.debian.org/debian trixie/main armhf file armhf 1:5.45-3 [42.0 kB] Get: 23 http://deb.debian.org/debian trixie/main armhf gettext-base armhf 0.21-14+b1 [157 kB] Get: 24 http://deb.debian.org/debian trixie/main armhf libuchardet0 armhf 0.0.8-1+b1 [65.7 kB] Get: 25 http://deb.debian.org/debian trixie/main armhf groff-base armhf 1.23.0-4 [1090 kB] Get: 26 http://deb.debian.org/debian trixie/main armhf bsdextrautils armhf 2.40-8 [85.6 kB] Get: 27 http://deb.debian.org/debian trixie/main armhf libpipeline1 armhf 1.5.7-2 [33.3 kB] Get: 28 http://deb.debian.org/debian trixie/main armhf man-db armhf 2.12.1-1 [1375 kB] Get: 29 http://deb.debian.org/debian trixie/main armhf m4 armhf 1.4.19-4 [264 kB] Get: 30 http://deb.debian.org/debian trixie/main armhf autoconf all 2.71-3 [332 kB] Get: 31 http://deb.debian.org/debian trixie/main armhf autotools-dev all 20220109.1 [51.6 kB] Get: 32 http://deb.debian.org/debian trixie/main armhf automake all 1:1.16.5-1.3 [823 kB] Get: 33 http://deb.debian.org/debian trixie/main armhf autopoint all 0.21-14 [496 kB] Get: 34 http://deb.debian.org/debian trixie/main armhf libdebhelper-perl all 13.15.3 [88.0 kB] Get: 35 http://deb.debian.org/debian trixie/main armhf libtool all 2.4.7-7 [517 kB] Get: 36 http://deb.debian.org/debian trixie/main armhf dh-autoreconf all 20 [17.1 kB] Get: 37 http://deb.debian.org/debian trixie/main armhf libarchive-zip-perl all 1.68-1 [104 kB] Get: 38 http://deb.debian.org/debian trixie/main armhf libsub-override-perl all 0.10-1 [10.6 kB] Get: 39 http://deb.debian.org/debian trixie/main armhf libfile-stripnondeterminism-perl all 1.13.1-1 [19.4 kB] Get: 40 http://deb.debian.org/debian trixie/main armhf dh-strip-nondeterminism all 1.13.1-1 [8620 B] Get: 41 http://deb.debian.org/debian trixie/main armhf libelf1t64 armhf 0.191-1+b1 [183 kB] Get: 42 http://deb.debian.org/debian trixie/main armhf dwz armhf 0.15-1+b2 [106 kB] Get: 43 http://deb.debian.org/debian trixie/main armhf libicu72 armhf 72.1-4+b1 [9070 kB] Get: 44 http://deb.debian.org/debian trixie/main armhf libxml2 armhf 2.9.14+dfsg-1.3+b3 [598 kB] Get: 45 http://deb.debian.org/debian trixie/main armhf gettext armhf 0.21-14+b1 [1230 kB] Get: 46 http://deb.debian.org/debian trixie/main armhf intltool-debian all 0.35.0+20060710.6 [22.9 kB] Get: 47 http://deb.debian.org/debian trixie/main armhf po-debconf all 1.0.21+nmu1 [248 kB] Get: 48 http://deb.debian.org/debian trixie/main armhf debhelper all 13.15.3 [901 kB] Get: 49 http://deb.debian.org/debian trixie/main armhf python3-pkg-resources all 68.1.2-2 [241 kB] Get: 50 http://deb.debian.org/debian trixie/main armhf python3-lib2to3 all 3.12.3-1 [77.6 kB] Get: 51 http://deb.debian.org/debian trixie/main armhf python3-distutils all 3.12.3-1 [131 kB] Get: 52 http://deb.debian.org/debian trixie/main armhf python3-setuptools all 68.1.2-2 [468 kB] Get: 53 http://deb.debian.org/debian trixie/main armhf dh-python all 6.20240422 [107 kB] Get: 54 http://deb.debian.org/debian trixie/main armhf fonts-font-awesome all 5.0.10+really4.7.0~dfsg-4.1 [517 kB] Get: 55 http://deb.debian.org/debian trixie/main armhf libbsd0 armhf 0.12.2-1 [127 kB] Get: 56 http://deb.debian.org/debian trixie/main armhf libcares2 armhf 1.28.1-1 [135 kB] Get: 57 http://deb.debian.org/debian trixie/main armhf libcom-err2 armhf 1.47.1~rc2-1 [21.8 kB] Get: 58 http://deb.debian.org/debian trixie/main armhf libev4t64 armhf 1:4.33-2.1 [37.6 kB] Get: 59 http://deb.debian.org/debian trixie/main armhf libkrb5support0 armhf 1.20.1-6+b1 [30.6 kB] Get: 60 http://deb.debian.org/debian trixie/main armhf libk5crypto3 armhf 1.20.1-6+b1 [75.5 kB] Get: 61 http://deb.debian.org/debian trixie/main armhf libkeyutils1 armhf 1.6.3-3 [7908 B] Get: 62 http://deb.debian.org/debian trixie/main armhf libkrb5-3 armhf 1.20.1-6+b1 [290 kB] Get: 63 http://deb.debian.org/debian trixie/main armhf libgssapi-krb5-2 armhf 1.20.1-6+b1 [112 kB] Get: 64 http://deb.debian.org/debian trixie/main armhf libjs-jquery all 3.6.1+dfsg+~3.5.14-1 [326 kB] Get: 65 http://deb.debian.org/debian trixie/main armhf libjs-underscore all 1.13.4~dfsg+~1.11.4-3 [116 kB] Get: 66 http://deb.debian.org/debian trixie/main armhf libjs-sphinxdoc all 7.2.6-6 [150 kB] Get: 67 http://deb.debian.org/debian trixie/main armhf libnorm1t64 armhf 1.5.9+dfsg-3.1 [186 kB] Get: 68 http://deb.debian.org/debian trixie/main armhf libpgm-5.3-0t64 armhf 5.3.128~dfsg-2.1 [154 kB] Get: 69 http://deb.debian.org/debian trixie/main armhf libpython3.12-stdlib armhf 3.12.3-1 [1808 kB] Get: 70 http://deb.debian.org/debian trixie/main armhf libsodium23 armhf 1.0.18-1+b1 [138 kB] Get: 71 http://deb.debian.org/debian trixie/main armhf libxslt1.1 armhf 1.1.35-1+b1 [212 kB] Get: 72 http://deb.debian.org/debian trixie/main armhf libzmq5 armhf 4.3.5-1+b2 [238 kB] Get: 73 http://deb.debian.org/debian trixie/main armhf python3-packaging all 24.0-1 [45.5 kB] Get: 74 http://deb.debian.org/debian trixie/main armhf python3-pyproject-hooks all 1.0.0-2 [10.6 kB] Get: 75 http://deb.debian.org/debian trixie/main armhf python3-toml all 0.10.2-1 [16.2 kB] Get: 76 http://deb.debian.org/debian trixie/main armhf python3-wheel all 0.43.0-1 [52.5 kB] Get: 77 http://deb.debian.org/debian trixie/main armhf python3-build all 1.1.1-1 [32.5 kB] Get: 78 http://deb.debian.org/debian trixie/main armhf python3-installer all 0.7.0+dfsg1-3 [18.6 kB] Get: 79 http://deb.debian.org/debian trixie/main armhf pybuild-plugin-pyproject all 6.20240422 [11.1 kB] Get: 80 http://deb.debian.org/debian trixie/main armhf python3.12 armhf 3.12.3-1 [659 kB] Get: 81 http://deb.debian.org/debian trixie/main armhf python3-all armhf 3.11.8-1 [1056 B] Get: 82 http://deb.debian.org/debian trixie/main armhf python3-blinker all 1.8.1-1 [13.1 kB] Get: 83 http://deb.debian.org/debian trixie/main armhf python3-brotli armhf 1.1.0-2+b3 [304 kB] Get: 84 http://deb.debian.org/debian trixie/main armhf python3-certifi all 2023.11.17-1 [155 kB] Get: 85 http://deb.debian.org/debian trixie/main armhf python3-cffi-backend armhf 1.16.0-2+b2 [99.1 kB] Get: 86 http://deb.debian.org/debian trixie/main armhf python3-chardet all 5.2.0+dfsg-1 [107 kB] Get: 87 http://deb.debian.org/debian trixie/main armhf python3-charset-normalizer all 3.3.2-1 [51.6 kB] Get: 88 http://deb.debian.org/debian trixie/main armhf python3-colorama all 0.4.6-4 [36.2 kB] Get: 89 http://deb.debian.org/debian trixie/main armhf python3-click all 8.1.7-1 [94.0 kB] Get: 90 http://deb.debian.org/debian trixie/main armhf python3-configargparse all 1.7-1 [31.3 kB] Get: 91 http://deb.debian.org/debian trixie/main armhf python3-cryptography armhf 42.0.5-2 [1002 kB] Get: 92 http://deb.debian.org/debian trixie/main armhf python3-cssselect all 1.2.0-4 [21.7 kB] Get: 93 http://deb.debian.org/debian trixie/main armhf python3-decorator all 5.1.1-5 [15.1 kB] Get: 94 http://deb.debian.org/debian trixie/main armhf python3-itsdangerous all 2.1.2-4 [17.1 kB] Get: 95 http://deb.debian.org/debian trixie/main armhf python3-markupsafe armhf 2.1.5-1 [13.9 kB] Get: 96 http://deb.debian.org/debian trixie/main armhf python3-jinja2 all 3.1.3-1 [119 kB] Get: 97 http://deb.debian.org/debian trixie/main armhf python3-werkzeug all 3.0.2-1 [206 kB] Get: 98 http://deb.debian.org/debian trixie/main armhf python3-flask all 3.0.3-1 [104 kB] Get: 99 http://deb.debian.org/debian trixie/main armhf sphinx-rtd-theme-common all 2.0.0+dfsg-1 [1021 kB] Get: 100 http://deb.debian.org/debian trixie/main armhf python3-flask-cors all 4.0.0-1 [44.1 kB] Get: 101 http://deb.debian.org/debian trixie/main armhf python3-flask-login all 0.6.3-2 [22.8 kB] Get: 102 http://deb.debian.org/debian trixie/main armhf python3-greenlet armhf 3.0.1-3 [171 kB] Get: 103 http://deb.debian.org/debian trixie/main armhf python3-zope.event all 5.0-0.1 [8164 B] Get: 104 http://deb.debian.org/debian trixie/main armhf python3-zope.interface armhf 6.1-1 [150 kB] Get: 105 http://deb.debian.org/debian trixie/main armhf python3-gevent armhf 24.2.1-0.1+b1 [1055 kB] Get: 106 http://deb.debian.org/debian trixie/main armhf python3-six all 1.16.0-6 [16.3 kB] Get: 107 http://deb.debian.org/debian trixie/main armhf python3-geventhttpclient armhf 2.0.11-2 [38.0 kB] Get: 108 http://deb.debian.org/debian trixie/main armhf python3-idna all 3.6-2 [37.0 kB] Get: 109 http://deb.debian.org/debian trixie/main armhf python3-iniconfig all 1.1.1-2 [6396 B] Get: 110 http://deb.debian.org/debian trixie/main armhf python3-lxml armhf 5.1.0-1 [1878 kB] Get: 111 http://deb.debian.org/debian trixie/main armhf python3-msgpack armhf 1.0.3-3+b1 [89.1 kB] Get: 112 http://deb.debian.org/debian trixie/main armhf python3-pluggy all 1.5.0-1 [26.9 kB] Get: 113 http://deb.debian.org/debian trixie/main armhf python3-psutil armhf 5.9.8-2 [225 kB] Get: 114 http://deb.debian.org/debian trixie/main armhf python3-py all 1.11.0-2 [88.7 kB] Get: 115 http://deb.debian.org/debian trixie/main armhf python3-webob all 1:1.8.7-1 [88.2 kB] Get: 116 http://deb.debian.org/debian trixie/main armhf python3-pyquery all 1.4.3-1 [23.1 kB] Get: 117 http://deb.debian.org/debian trixie/main armhf python3-pytest all 7.4.4-3 [239 kB] Get: 118 http://deb.debian.org/debian trixie/main armhf python3-urllib3 all 1.26.18-2 [116 kB] Get: 119 http://deb.debian.org/debian trixie/main armhf python3-requests all 2.31.0+dfsg-1 [68.6 kB] Get: 120 http://deb.debian.org/debian trixie/main armhf python3-retry all 0.9.2-2 [7020 B] Get: 121 http://deb.debian.org/debian trixie/main armhf python3-roundrobin all 0.0.4-3 [4364 B] Get: 122 http://deb.debian.org/debian trixie/main armhf python3-typing-extensions all 4.10.0-1 [66.2 kB] Get: 123 http://deb.debian.org/debian trixie/main armhf python3-zmq armhf 24.0.1-5+b1 [326 kB] Fetched 45.3 MB in 4s (12.1 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 ... 19444 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:armhf. Preparing to unpack .../libpython3.11-minimal_3.11.9-1_armhf.deb ... Unpacking libpython3.11-minimal:armhf (3.11.9-1) ... Selecting previously unselected package libexpat1:armhf. Preparing to unpack .../libexpat1_2.6.2-1_armhf.deb ... Unpacking libexpat1:armhf (2.6.2-1) ... Selecting previously unselected package python3.11-minimal. Preparing to unpack .../python3.11-minimal_3.11.9-1_armhf.deb ... Unpacking python3.11-minimal (3.11.9-1) ... Setting up libpython3.11-minimal:armhf (3.11.9-1) ... Setting up libexpat1:armhf (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 ... 19786 files and directories currently installed.) Preparing to unpack .../0-python3-minimal_3.11.8-1_armhf.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:armhf. Preparing to unpack .../5-libreadline8t64_8.2-4_armhf.deb ... Adding 'diversion of /lib/arm-linux-gnueabihf/libhistory.so.8 to /lib/arm-linux-gnueabihf/libhistory.so.8.usr-is-merged by libreadline8t64' Adding 'diversion of /lib/arm-linux-gnueabihf/libhistory.so.8.2 to /lib/arm-linux-gnueabihf/libhistory.so.8.2.usr-is-merged by libreadline8t64' Adding 'diversion of /lib/arm-linux-gnueabihf/libreadline.so.8 to /lib/arm-linux-gnueabihf/libreadline.so.8.usr-is-merged by libreadline8t64' Adding 'diversion of /lib/arm-linux-gnueabihf/libreadline.so.8.2 to /lib/arm-linux-gnueabihf/libreadline.so.8.2.usr-is-merged by libreadline8t64' Unpacking libreadline8t64:armhf (8.2-4) ... Selecting previously unselected package libpython3.11-stdlib:armhf. Preparing to unpack .../6-libpython3.11-stdlib_3.11.9-1_armhf.deb ... Unpacking libpython3.11-stdlib:armhf (3.11.9-1) ... Selecting previously unselected package python3.11. Preparing to unpack .../7-python3.11_3.11.9-1_armhf.deb ... Unpacking python3.11 (3.11.9-1) ... Selecting previously unselected package libpython3-stdlib:armhf. Preparing to unpack .../8-libpython3-stdlib_3.11.8-1_armhf.deb ... Unpacking libpython3-stdlib:armhf (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 ... 20778 files and directories currently installed.) Preparing to unpack .../000-python3_3.11.8-1_armhf.deb ... Unpacking python3 (3.11.8-1) ... Selecting previously unselected package libpython3.12-minimal:armhf. Preparing to unpack .../001-libpython3.12-minimal_3.12.3-1_armhf.deb ... Unpacking libpython3.12-minimal:armhf (3.12.3-1) ... Selecting previously unselected package python3.12-minimal. Preparing to unpack .../002-python3.12-minimal_3.12.3-1_armhf.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_armhf.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_armhf.deb ... Unpacking libmagic-mgc (1:5.45-3) ... Selecting previously unselected package libmagic1t64:armhf. Preparing to unpack .../007-libmagic1t64_1%3a5.45-3_armhf.deb ... Unpacking libmagic1t64:armhf (1:5.45-3) ... Selecting previously unselected package file. Preparing to unpack .../008-file_1%3a5.45-3_armhf.deb ... Unpacking file (1:5.45-3) ... Selecting previously unselected package gettext-base. Preparing to unpack .../009-gettext-base_0.21-14+b1_armhf.deb ... Unpacking gettext-base (0.21-14+b1) ... Selecting previously unselected package libuchardet0:armhf. Preparing to unpack .../010-libuchardet0_0.0.8-1+b1_armhf.deb ... Unpacking libuchardet0:armhf (0.0.8-1+b1) ... Selecting previously unselected package groff-base. Preparing to unpack .../011-groff-base_1.23.0-4_armhf.deb ... Unpacking groff-base (1.23.0-4) ... Selecting previously unselected package bsdextrautils. Preparing to unpack .../012-bsdextrautils_2.40-8_armhf.deb ... Unpacking bsdextrautils (2.40-8) ... Selecting previously unselected package libpipeline1:armhf. Preparing to unpack .../013-libpipeline1_1.5.7-2_armhf.deb ... Unpacking libpipeline1:armhf (1.5.7-2) ... Selecting previously unselected package man-db. Preparing to unpack .../014-man-db_2.12.1-1_armhf.deb ... Unpacking man-db (2.12.1-1) ... Selecting previously unselected package m4. Preparing to unpack .../015-m4_1.4.19-4_armhf.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:armhf. Preparing to unpack .../027-libelf1t64_0.191-1+b1_armhf.deb ... Unpacking libelf1t64:armhf (0.191-1+b1) ... Selecting previously unselected package dwz. Preparing to unpack .../028-dwz_0.15-1+b2_armhf.deb ... Unpacking dwz (0.15-1+b2) ... Selecting previously unselected package libicu72:armhf. Preparing to unpack .../029-libicu72_72.1-4+b1_armhf.deb ... Unpacking libicu72:armhf (72.1-4+b1) ... Selecting previously unselected package libxml2:armhf. Preparing to unpack .../030-libxml2_2.9.14+dfsg-1.3+b3_armhf.deb ... Unpacking libxml2:armhf (2.9.14+dfsg-1.3+b3) ... Selecting previously unselected package gettext. Preparing to unpack .../031-gettext_0.21-14+b1_armhf.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:armhf. Preparing to unpack .../041-libbsd0_0.12.2-1_armhf.deb ... Unpacking libbsd0:armhf (0.12.2-1) ... Selecting previously unselected package libcares2:armhf. Preparing to unpack .../042-libcares2_1.28.1-1_armhf.deb ... Unpacking libcares2:armhf (1.28.1-1) ... Selecting previously unselected package libcom-err2:armhf. Preparing to unpack .../043-libcom-err2_1.47.1~rc2-1_armhf.deb ... Unpacking libcom-err2:armhf (1.47.1~rc2-1) ... Selecting previously unselected package libev4t64:armhf. Preparing to unpack .../044-libev4t64_1%3a4.33-2.1_armhf.deb ... Unpacking libev4t64:armhf (1:4.33-2.1) ... Selecting previously unselected package libkrb5support0:armhf. Preparing to unpack .../045-libkrb5support0_1.20.1-6+b1_armhf.deb ... Unpacking libkrb5support0:armhf (1.20.1-6+b1) ... Selecting previously unselected package libk5crypto3:armhf. Preparing to unpack .../046-libk5crypto3_1.20.1-6+b1_armhf.deb ... Unpacking libk5crypto3:armhf (1.20.1-6+b1) ... Selecting previously unselected package libkeyutils1:armhf. Preparing to unpack .../047-libkeyutils1_1.6.3-3_armhf.deb ... Unpacking libkeyutils1:armhf (1.6.3-3) ... Selecting previously unselected package libkrb5-3:armhf. Preparing to unpack .../048-libkrb5-3_1.20.1-6+b1_armhf.deb ... Unpacking libkrb5-3:armhf (1.20.1-6+b1) ... Selecting previously unselected package libgssapi-krb5-2:armhf. Preparing to unpack .../049-libgssapi-krb5-2_1.20.1-6+b1_armhf.deb ... Unpacking libgssapi-krb5-2:armhf (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:armhf. Preparing to unpack .../053-libnorm1t64_1.5.9+dfsg-3.1_armhf.deb ... Unpacking libnorm1t64:armhf (1.5.9+dfsg-3.1) ... Selecting previously unselected package libpgm-5.3-0t64:armhf. Preparing to unpack .../054-libpgm-5.3-0t64_5.3.128~dfsg-2.1_armhf.deb ... Unpacking libpgm-5.3-0t64:armhf (5.3.128~dfsg-2.1) ... Selecting previously unselected package libpython3.12-stdlib:armhf. Preparing to unpack .../055-libpython3.12-stdlib_3.12.3-1_armhf.deb ... Unpacking libpython3.12-stdlib:armhf (3.12.3-1) ... Selecting previously unselected package libsodium23:armhf. Preparing to unpack .../056-libsodium23_1.0.18-1+b1_armhf.deb ... Unpacking libsodium23:armhf (1.0.18-1+b1) ... Selecting previously unselected package libxslt1.1:armhf. Preparing to unpack .../057-libxslt1.1_1.1.35-1+b1_armhf.deb ... Unpacking libxslt1.1:armhf (1.1.35-1+b1) ... Selecting previously unselected package libzmq5:armhf. Preparing to unpack .../058-libzmq5_4.3.5-1+b2_armhf.deb ... Unpacking libzmq5:armhf (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.1.1-1_all.deb ... Unpacking python3-build (1.1.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_armhf.deb ... Unpacking python3.12 (3.12.3-1) ... Selecting previously unselected package python3-all. Preparing to unpack .../067-python3-all_3.11.8-1_armhf.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_armhf.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:armhf. Preparing to unpack .../071-python3-cffi-backend_1.16.0-2+b2_armhf.deb ... Unpacking python3-cffi-backend:armhf (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_armhf.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_armhf.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_armhf.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_armhf.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_armhf.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_armhf.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:armhf. Preparing to unpack .../096-python3-lxml_5.1.0-1_armhf.deb ... Unpacking python3-lxml:armhf (5.1.0-1) ... Selecting previously unselected package python3-msgpack. Preparing to unpack .../097-python3-msgpack_1.0.3-3+b1_armhf.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_armhf.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_armhf.deb ... Unpacking python3-zmq (24.0.1-5+b1) ... Setting up media-types (10.1.0) ... Setting up libpipeline1:armhf (1.5.7-2) ... Setting up libev4t64:armhf (1:4.33-2.1) ... Setting up libnorm1t64:armhf (1.5.9+dfsg-3.1) ... Setting up libkeyutils1:armhf (1.6.3-3) ... Setting up fonts-lato (2.015-1) ... Setting up libsodium23:armhf (1.0.18-1+b1) ... Setting up libicu72:armhf (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:armhf (1:5.45-3) ... Setting up libpython3.12-minimal:armhf (3.12.3-1) ... Setting up gettext-base (0.21-14+b1) ... Setting up m4 (1.4.19-4) ... Setting up libcom-err2:armhf (1.47.1~rc2-1) ... Setting up file (1:5.45-3) ... Setting up libelf1t64:armhf (0.191-1+b1) ... Setting up libkrb5support0:armhf (1.20.1-6+b1) ... Setting up tzdata (2024a-4) ... Current default time zone: 'Etc/UTC' Local time is now: Thu May 9 02:39:10 UTC 2024. Universal Time is now: Thu May 9 02:39:10 UTC 2024. Run 'dpkg-reconfigure tzdata' if you wish to change it. Setting up libpgm-5.3-0t64:armhf (5.3.128~dfsg-2.1) ... Setting up autotools-dev (20220109.1) ... Setting up libcares2:armhf (1.28.1-1) ... Setting up autopoint (0.21-14) ... Setting up libk5crypto3:armhf (1.20.1-6+b1) ... Setting up autoconf (2.71-3) ... Setting up dwz (0.15-1+b2) ... Setting up sensible-utils (0.0.22) ... Setting up libuchardet0:armhf (0.0.8-1+b1) ... Setting up libsub-override-perl (0.10-1) ... Setting up netbase (6.4) ... Setting up libkrb5-3:armhf (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:armhf (0.12.2-1) ... Setting up readline-common (8.2-4) ... Setting up libxml2:armhf (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:armhf (1.20.1-6+b1) ... Setting up libjs-sphinxdoc (7.2.6-6) ... Setting up libreadline8t64:armhf (8.2-4) ... Setting up dh-strip-nondeterminism (1.13.1-1) ... Setting up groff-base (1.23.0-4) ... Setting up libxslt1.1:armhf (1.1.35-1+b1) ... Setting up libzmq5:armhf (4.3.5-1+b2) ... Setting up libpython3.12-stdlib:armhf (3.12.3-1) ... Setting up po-debconf (1.0.21+nmu1) ... Setting up libpython3.11-stdlib:armhf (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:armhf (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:armhf (5.1.0-1) ... Setting up python3-msgpack (1.0.3-3+b1) ... Setting up python3-build (1.1.1-1) ... Setting up python3-cssselect (1.2.0-4) ... Setting up python3-lib2to3 (3.12.3-1) ... Setting up python3-cffi-backend:armhf (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: Running cd /build/reproducible-path/locust-2.24.0/ && env PATH="/usr/sbin:/usr/bin:/sbin:/bin:/usr/games" HOME="/nonexistent/first-build" dpkg-buildpackage -us -uc -b && env PATH="/usr/sbin:/usr/bin:/sbin:/bin:/usr/games" HOME="/nonexistent/first-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 armhf 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/env.py -> build/lib/locust copying locust/shape.py -> build/lib/locust copying locust/runners.py -> build/lib/locust copying locust/input_events.py -> build/lib/locust copying locust/web.py -> build/lib/locust copying locust/event.py -> build/lib/locust copying locust/_version.py -> build/lib/locust copying locust/debug.py -> build/lib/locust copying locust/__main__.py -> build/lib/locust copying locust/__init__.py -> build/lib/locust copying locust/html.py -> build/lib/locust copying locust/dispatch.py -> build/lib/locust copying locust/stats.py -> build/lib/locust copying locust/argument_parser.py -> build/lib/locust copying locust/clients.py -> build/lib/locust copying locust/log.py -> build/lib/locust copying locust/exception.py -> build/lib/locust copying locust/main.py -> build/lib/locust creating build/lib/locust/rpc copying locust/rpc/protocol.py -> build/lib/locust/rpc copying locust/rpc/zmqrpc.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 creating build/lib/locust/user copying locust/user/wait_time.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 copying locust/user/users.py -> build/lib/locust/user copying locust/user/task.py -> build/lib/locust/user creating build/lib/locust/util copying locust/util/deprecation.py -> build/lib/locust/util copying locust/util/load_locustfile.py -> build/lib/locust/util copying locust/util/__init__.py -> build/lib/locust/util copying locust/util/cache.py -> build/lib/locust/util copying locust/util/rounding.py -> build/lib/locust/util copying locust/util/exception_handler.py -> build/lib/locust/util copying locust/util/timespan.py -> build/lib/locust/util creating build/lib/locust/test copying locust/test/test_load_locustfile.py -> build/lib/locust/test copying locust/test/test_stats.py -> build/lib/locust/test copying locust/test/test_parser.py -> build/lib/locust/test copying locust/test/test_tags.py -> build/lib/locust/test copying locust/test/test_locust_class.py -> build/lib/locust/test copying locust/test/test_web.py -> build/lib/locust/test copying locust/test/test_taskratio.py -> build/lib/locust/test copying locust/test/test_env.py -> build/lib/locust/test copying locust/test/test_interruptable_task.py -> build/lib/locust/test copying locust/test/test_util.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 copying locust/test/test_debugging.py -> build/lib/locust/test copying locust/test/test_old_wait_api.py -> build/lib/locust/test copying locust/test/test_dispatch.py -> build/lib/locust/test copying locust/test/test_sequential_taskset.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_runners.py -> build/lib/locust/test copying locust/test/fake_module2_for_env_test.py -> build/lib/locust/test copying locust/test/test_users.py -> build/lib/locust/test copying locust/test/mock_locustfile.py -> build/lib/locust/test copying locust/test/test_http.py -> build/lib/locust/test copying locust/test/test_wait_time.py -> build/lib/locust/test copying locust/test/mock_logging.py -> build/lib/locust/test copying locust/test/test_fasthttp.py -> build/lib/locust/test copying locust/test/test_zmqrpc.py -> build/lib/locust/test copying locust/test/testcases.py -> build/lib/locust/test copying locust/test/util.py -> build/lib/locust/test copying locust/py.typed -> build/lib/locust creating build/lib/locust/templates copying locust/templates/index.html -> build/lib/locust/templates copying locust/templates/report.html -> build/lib/locust/templates copying locust/templates/stats_data.html -> build/lib/locust/templates creating build/lib/locust/static copying locust/static/vintage.js -> build/lib/locust/static copying locust/static/jquery-1.11.3.min.js -> build/lib/locust/static copying locust/static/locust.js -> build/lib/locust/static copying locust/static/echarts.common.min.js -> build/lib/locust/static copying locust/static/jquery.tools.min.js -> build/lib/locust/static copying locust/static/tasks.js -> build/lib/locust/static copying locust/static/chart.js -> build/lib/locust/static copying locust/static/jquery.jqote2.min.js -> build/lib/locust/static creating build/lib/locust/static/sass copying locust/static/sass/application.sass -> build/lib/locust/static/sass copying locust/static/sass/tables.sass -> build/lib/locust/static/sass copying locust/static/sass/_base.sass -> build/lib/locust/static/sass copying locust/static/sass/_mixins.sass -> build/lib/locust/static/sass creating build/lib/locust/static/img copying locust/static/img/favicon.ico -> 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/ui-screenshot-workers.png -> build/lib/locust/static/img copying locust/static/img/logo.png -> build/lib/locust/static/img copying locust/static/img/ui-screenshot-stats.png -> build/lib/locust/static/img creating 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 copying locust/static/css/tables.css.map -> build/lib/locust/static/css copying locust/static/css/tables.css -> build/lib/locust/static/css creating build/lib/locust/webui creating build/lib/locust/webui/dist copying locust/webui/dist/auth.html -> build/lib/locust/webui/dist copying locust/webui/dist/index.html -> build/lib/locust/webui/dist copying locust/webui/dist/report.html -> build/lib/locust/webui/dist creating 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 copying locust/webui/dist/assets/logo.png -> build/lib/locust/webui/dist/assets installing to build/bdist.linux-armv7l/wheel running install running install_lib creating build/bdist.linux-armv7l creating build/bdist.linux-armv7l/wheel creating build/bdist.linux-armv7l/wheel/locust copying build/lib/locust/env.py -> build/bdist.linux-armv7l/wheel/locust creating build/bdist.linux-armv7l/wheel/locust/templates copying build/lib/locust/templates/index.html -> build/bdist.linux-armv7l/wheel/locust/templates copying build/lib/locust/templates/report.html -> build/bdist.linux-armv7l/wheel/locust/templates copying build/lib/locust/templates/stats_data.html -> build/bdist.linux-armv7l/wheel/locust/templates creating build/bdist.linux-armv7l/wheel/locust/rpc copying build/lib/locust/rpc/protocol.py -> build/bdist.linux-armv7l/wheel/locust/rpc copying build/lib/locust/rpc/zmqrpc.py -> build/bdist.linux-armv7l/wheel/locust/rpc copying build/lib/locust/rpc/__init__.py -> build/bdist.linux-armv7l/wheel/locust/rpc copying build/lib/locust/shape.py -> build/bdist.linux-armv7l/wheel/locust copying build/lib/locust/runners.py -> build/bdist.linux-armv7l/wheel/locust creating build/bdist.linux-armv7l/wheel/locust/contrib copying build/lib/locust/contrib/fasthttp.py -> build/bdist.linux-armv7l/wheel/locust/contrib copying build/lib/locust/contrib/__init__.py -> build/bdist.linux-armv7l/wheel/locust/contrib copying build/lib/locust/input_events.py -> build/bdist.linux-armv7l/wheel/locust copying build/lib/locust/web.py -> build/bdist.linux-armv7l/wheel/locust creating build/bdist.linux-armv7l/wheel/locust/user copying build/lib/locust/user/wait_time.py -> build/bdist.linux-armv7l/wheel/locust/user copying build/lib/locust/user/sequential_taskset.py -> build/bdist.linux-armv7l/wheel/locust/user copying build/lib/locust/user/inspectuser.py -> build/bdist.linux-armv7l/wheel/locust/user copying build/lib/locust/user/__init__.py -> build/bdist.linux-armv7l/wheel/locust/user copying build/lib/locust/user/users.py -> build/bdist.linux-armv7l/wheel/locust/user copying build/lib/locust/user/task.py -> build/bdist.linux-armv7l/wheel/locust/user copying build/lib/locust/event.py -> build/bdist.linux-armv7l/wheel/locust copying build/lib/locust/_version.py -> build/bdist.linux-armv7l/wheel/locust creating build/bdist.linux-armv7l/wheel/locust/webui creating build/bdist.linux-armv7l/wheel/locust/webui/dist copying build/lib/locust/webui/dist/auth.html -> build/bdist.linux-armv7l/wheel/locust/webui/dist copying build/lib/locust/webui/dist/index.html -> build/bdist.linux-armv7l/wheel/locust/webui/dist copying build/lib/locust/webui/dist/report.html -> build/bdist.linux-armv7l/wheel/locust/webui/dist creating build/bdist.linux-armv7l/wheel/locust/webui/dist/assets copying build/lib/locust/webui/dist/assets/index-0d6d578a.js -> build/bdist.linux-armv7l/wheel/locust/webui/dist/assets copying build/lib/locust/webui/dist/assets/favicon.ico -> build/bdist.linux-armv7l/wheel/locust/webui/dist/assets copying build/lib/locust/webui/dist/assets/logo.png -> build/bdist.linux-armv7l/wheel/locust/webui/dist/assets copying build/lib/locust/debug.py -> build/bdist.linux-armv7l/wheel/locust copying build/lib/locust/__main__.py -> build/bdist.linux-armv7l/wheel/locust copying build/lib/locust/__init__.py -> build/bdist.linux-armv7l/wheel/locust copying build/lib/locust/html.py -> build/bdist.linux-armv7l/wheel/locust copying build/lib/locust/py.typed -> build/bdist.linux-armv7l/wheel/locust creating build/bdist.linux-armv7l/wheel/locust/static copying build/lib/locust/static/vintage.js -> build/bdist.linux-armv7l/wheel/locust/static creating build/bdist.linux-armv7l/wheel/locust/static/sass copying build/lib/locust/static/sass/application.sass -> build/bdist.linux-armv7l/wheel/locust/static/sass copying build/lib/locust/static/sass/tables.sass -> build/bdist.linux-armv7l/wheel/locust/static/sass copying build/lib/locust/static/sass/_base.sass -> build/bdist.linux-armv7l/wheel/locust/static/sass copying build/lib/locust/static/sass/_mixins.sass -> build/bdist.linux-armv7l/wheel/locust/static/sass copying build/lib/locust/static/jquery-1.11.3.min.js -> build/bdist.linux-armv7l/wheel/locust/static creating build/bdist.linux-armv7l/wheel/locust/static/img copying build/lib/locust/static/img/favicon.ico -> build/bdist.linux-armv7l/wheel/locust/static/img copying build/lib/locust/static/img/ui-screenshot-start-test.png -> build/bdist.linux-armv7l/wheel/locust/static/img copying build/lib/locust/static/img/ui-screenshot-charts.png -> build/bdist.linux-armv7l/wheel/locust/static/img copying build/lib/locust/static/img/ui-screenshot-workers.png -> build/bdist.linux-armv7l/wheel/locust/static/img copying build/lib/locust/static/img/logo.png -> build/bdist.linux-armv7l/wheel/locust/static/img copying build/lib/locust/static/img/ui-screenshot-stats.png -> build/bdist.linux-armv7l/wheel/locust/static/img copying build/lib/locust/static/locust.js -> build/bdist.linux-armv7l/wheel/locust/static copying build/lib/locust/static/echarts.common.min.js -> build/bdist.linux-armv7l/wheel/locust/static copying build/lib/locust/static/jquery.tools.min.js -> build/bdist.linux-armv7l/wheel/locust/static copying build/lib/locust/static/tasks.js -> build/bdist.linux-armv7l/wheel/locust/static creating build/bdist.linux-armv7l/wheel/locust/static/css copying build/lib/locust/static/css/application.css.map -> build/bdist.linux-armv7l/wheel/locust/static/css copying build/lib/locust/static/css/application.css -> build/bdist.linux-armv7l/wheel/locust/static/css copying build/lib/locust/static/css/tables.css.map -> build/bdist.linux-armv7l/wheel/locust/static/css copying build/lib/locust/static/css/tables.css -> build/bdist.linux-armv7l/wheel/locust/static/css copying build/lib/locust/static/chart.js -> build/bdist.linux-armv7l/wheel/locust/static copying build/lib/locust/static/jquery.jqote2.min.js -> build/bdist.linux-armv7l/wheel/locust/static copying build/lib/locust/dispatch.py -> build/bdist.linux-armv7l/wheel/locust copying build/lib/locust/stats.py -> build/bdist.linux-armv7l/wheel/locust copying build/lib/locust/argument_parser.py -> build/bdist.linux-armv7l/wheel/locust creating build/bdist.linux-armv7l/wheel/locust/util copying build/lib/locust/util/deprecation.py -> build/bdist.linux-armv7l/wheel/locust/util copying build/lib/locust/util/load_locustfile.py -> build/bdist.linux-armv7l/wheel/locust/util copying build/lib/locust/util/__init__.py -> build/bdist.linux-armv7l/wheel/locust/util copying build/lib/locust/util/cache.py -> build/bdist.linux-armv7l/wheel/locust/util copying build/lib/locust/util/rounding.py -> build/bdist.linux-armv7l/wheel/locust/util copying build/lib/locust/util/exception_handler.py -> build/bdist.linux-armv7l/wheel/locust/util copying build/lib/locust/util/timespan.py -> build/bdist.linux-armv7l/wheel/locust/util copying build/lib/locust/clients.py -> build/bdist.linux-armv7l/wheel/locust copying build/lib/locust/log.py -> build/bdist.linux-armv7l/wheel/locust copying build/lib/locust/exception.py -> build/bdist.linux-armv7l/wheel/locust creating build/bdist.linux-armv7l/wheel/locust/test copying build/lib/locust/test/test_load_locustfile.py -> build/bdist.linux-armv7l/wheel/locust/test copying build/lib/locust/test/test_stats.py -> build/bdist.linux-armv7l/wheel/locust/test copying build/lib/locust/test/test_parser.py -> build/bdist.linux-armv7l/wheel/locust/test copying build/lib/locust/test/test_tags.py -> build/bdist.linux-armv7l/wheel/locust/test copying build/lib/locust/test/test_locust_class.py -> build/bdist.linux-armv7l/wheel/locust/test copying build/lib/locust/test/test_web.py -> build/bdist.linux-armv7l/wheel/locust/test copying build/lib/locust/test/test_taskratio.py -> build/bdist.linux-armv7l/wheel/locust/test copying build/lib/locust/test/test_env.py -> build/bdist.linux-armv7l/wheel/locust/test copying build/lib/locust/test/test_interruptable_task.py -> build/bdist.linux-armv7l/wheel/locust/test copying build/lib/locust/test/test_util.py -> build/bdist.linux-armv7l/wheel/locust/test copying build/lib/locust/test/fake_module1_for_env_test.py -> build/bdist.linux-armv7l/wheel/locust/test copying build/lib/locust/test/__init__.py -> build/bdist.linux-armv7l/wheel/locust/test copying build/lib/locust/test/test_debugging.py -> build/bdist.linux-armv7l/wheel/locust/test copying build/lib/locust/test/test_old_wait_api.py -> build/bdist.linux-armv7l/wheel/locust/test copying build/lib/locust/test/test_dispatch.py -> build/bdist.linux-armv7l/wheel/locust/test copying build/lib/locust/test/test_sequential_taskset.py -> build/bdist.linux-armv7l/wheel/locust/test copying build/lib/locust/test/test_main.py -> build/bdist.linux-armv7l/wheel/locust/test copying build/lib/locust/test/test_log.py -> build/bdist.linux-armv7l/wheel/locust/test copying build/lib/locust/test/test_runners.py -> build/bdist.linux-armv7l/wheel/locust/test copying build/lib/locust/test/fake_module2_for_env_test.py -> build/bdist.linux-armv7l/wheel/locust/test copying build/lib/locust/test/test_users.py -> build/bdist.linux-armv7l/wheel/locust/test copying build/lib/locust/test/mock_locustfile.py -> build/bdist.linux-armv7l/wheel/locust/test copying build/lib/locust/test/test_http.py -> build/bdist.linux-armv7l/wheel/locust/test copying build/lib/locust/test/test_wait_time.py -> build/bdist.linux-armv7l/wheel/locust/test copying build/lib/locust/test/mock_logging.py -> build/bdist.linux-armv7l/wheel/locust/test copying build/lib/locust/test/test_fasthttp.py -> build/bdist.linux-armv7l/wheel/locust/test copying build/lib/locust/test/test_zmqrpc.py -> build/bdist.linux-armv7l/wheel/locust/test copying build/lib/locust/test/testcases.py -> build/bdist.linux-armv7l/wheel/locust/test copying build/lib/locust/test/util.py -> build/bdist.linux-armv7l/wheel/locust/test copying build/lib/locust/main.py -> build/bdist.linux-armv7l/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-armv7l/wheel/locust-0.0.0.egg-info running install_scripts creating build/bdist.linux-armv7l/wheel/locust-0.0.0.dist-info/WHEEL creating '/build/reproducible-path/locust-2.24.0/.pybuild/cpython3_3.12_locust/.tmp-aodbiajb/locust-0.0.0-py3-none-any.whl' and adding 'build/bdist.linux-armv7l/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-armv7l/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-armv7l/wheel running install running install_lib creating build/bdist.linux-armv7l/wheel creating build/bdist.linux-armv7l/wheel/locust copying build/lib/locust/env.py -> build/bdist.linux-armv7l/wheel/locust creating build/bdist.linux-armv7l/wheel/locust/templates copying build/lib/locust/templates/index.html -> build/bdist.linux-armv7l/wheel/locust/templates copying build/lib/locust/templates/report.html -> build/bdist.linux-armv7l/wheel/locust/templates copying build/lib/locust/templates/stats_data.html -> build/bdist.linux-armv7l/wheel/locust/templates creating build/bdist.linux-armv7l/wheel/locust/rpc copying build/lib/locust/rpc/protocol.py -> build/bdist.linux-armv7l/wheel/locust/rpc copying build/lib/locust/rpc/zmqrpc.py -> build/bdist.linux-armv7l/wheel/locust/rpc copying build/lib/locust/rpc/__init__.py -> build/bdist.linux-armv7l/wheel/locust/rpc copying build/lib/locust/shape.py -> build/bdist.linux-armv7l/wheel/locust copying build/lib/locust/runners.py -> build/bdist.linux-armv7l/wheel/locust creating build/bdist.linux-armv7l/wheel/locust/contrib copying build/lib/locust/contrib/fasthttp.py -> build/bdist.linux-armv7l/wheel/locust/contrib copying build/lib/locust/contrib/__init__.py -> build/bdist.linux-armv7l/wheel/locust/contrib copying build/lib/locust/input_events.py -> build/bdist.linux-armv7l/wheel/locust copying build/lib/locust/web.py -> build/bdist.linux-armv7l/wheel/locust creating build/bdist.linux-armv7l/wheel/locust/user copying build/lib/locust/user/wait_time.py -> build/bdist.linux-armv7l/wheel/locust/user copying build/lib/locust/user/sequential_taskset.py -> build/bdist.linux-armv7l/wheel/locust/user copying build/lib/locust/user/inspectuser.py -> build/bdist.linux-armv7l/wheel/locust/user copying build/lib/locust/user/__init__.py -> build/bdist.linux-armv7l/wheel/locust/user copying build/lib/locust/user/users.py -> build/bdist.linux-armv7l/wheel/locust/user copying build/lib/locust/user/task.py -> build/bdist.linux-armv7l/wheel/locust/user copying build/lib/locust/event.py -> build/bdist.linux-armv7l/wheel/locust copying build/lib/locust/_version.py -> build/bdist.linux-armv7l/wheel/locust creating build/bdist.linux-armv7l/wheel/locust/webui creating build/bdist.linux-armv7l/wheel/locust/webui/dist copying build/lib/locust/webui/dist/auth.html -> build/bdist.linux-armv7l/wheel/locust/webui/dist copying build/lib/locust/webui/dist/index.html -> build/bdist.linux-armv7l/wheel/locust/webui/dist copying build/lib/locust/webui/dist/report.html -> build/bdist.linux-armv7l/wheel/locust/webui/dist creating build/bdist.linux-armv7l/wheel/locust/webui/dist/assets copying build/lib/locust/webui/dist/assets/index-0d6d578a.js -> build/bdist.linux-armv7l/wheel/locust/webui/dist/assets copying build/lib/locust/webui/dist/assets/favicon.ico -> build/bdist.linux-armv7l/wheel/locust/webui/dist/assets copying build/lib/locust/webui/dist/assets/logo.png -> build/bdist.linux-armv7l/wheel/locust/webui/dist/assets copying build/lib/locust/debug.py -> build/bdist.linux-armv7l/wheel/locust copying build/lib/locust/__main__.py -> build/bdist.linux-armv7l/wheel/locust copying build/lib/locust/__init__.py -> build/bdist.linux-armv7l/wheel/locust copying build/lib/locust/html.py -> build/bdist.linux-armv7l/wheel/locust copying build/lib/locust/py.typed -> build/bdist.linux-armv7l/wheel/locust creating build/bdist.linux-armv7l/wheel/locust/static copying build/lib/locust/static/vintage.js -> build/bdist.linux-armv7l/wheel/locust/static creating build/bdist.linux-armv7l/wheel/locust/static/sass copying build/lib/locust/static/sass/application.sass -> build/bdist.linux-armv7l/wheel/locust/static/sass copying build/lib/locust/static/sass/tables.sass -> build/bdist.linux-armv7l/wheel/locust/static/sass copying build/lib/locust/static/sass/_base.sass -> build/bdist.linux-armv7l/wheel/locust/static/sass copying build/lib/locust/static/sass/_mixins.sass -> build/bdist.linux-armv7l/wheel/locust/static/sass copying build/lib/locust/static/jquery-1.11.3.min.js -> build/bdist.linux-armv7l/wheel/locust/static creating build/bdist.linux-armv7l/wheel/locust/static/img copying build/lib/locust/static/img/favicon.ico -> build/bdist.linux-armv7l/wheel/locust/static/img copying build/lib/locust/static/img/ui-screenshot-start-test.png -> build/bdist.linux-armv7l/wheel/locust/static/img copying build/lib/locust/static/img/ui-screenshot-charts.png -> build/bdist.linux-armv7l/wheel/locust/static/img copying build/lib/locust/static/img/ui-screenshot-workers.png -> build/bdist.linux-armv7l/wheel/locust/static/img copying build/lib/locust/static/img/logo.png -> build/bdist.linux-armv7l/wheel/locust/static/img copying build/lib/locust/static/img/ui-screenshot-stats.png -> build/bdist.linux-armv7l/wheel/locust/static/img copying build/lib/locust/static/locust.js -> build/bdist.linux-armv7l/wheel/locust/static copying build/lib/locust/static/echarts.common.min.js -> build/bdist.linux-armv7l/wheel/locust/static copying build/lib/locust/static/jquery.tools.min.js -> build/bdist.linux-armv7l/wheel/locust/static copying build/lib/locust/static/tasks.js -> build/bdist.linux-armv7l/wheel/locust/static creating build/bdist.linux-armv7l/wheel/locust/static/css copying build/lib/locust/static/css/application.css.map -> build/bdist.linux-armv7l/wheel/locust/static/css copying build/lib/locust/static/css/application.css -> build/bdist.linux-armv7l/wheel/locust/static/css copying build/lib/locust/static/css/tables.css.map -> build/bdist.linux-armv7l/wheel/locust/static/css copying build/lib/locust/static/css/tables.css -> build/bdist.linux-armv7l/wheel/locust/static/css copying build/lib/locust/static/chart.js -> build/bdist.linux-armv7l/wheel/locust/static copying build/lib/locust/static/jquery.jqote2.min.js -> build/bdist.linux-armv7l/wheel/locust/static copying build/lib/locust/dispatch.py -> build/bdist.linux-armv7l/wheel/locust copying build/lib/locust/stats.py -> build/bdist.linux-armv7l/wheel/locust copying build/lib/locust/argument_parser.py -> build/bdist.linux-armv7l/wheel/locust creating build/bdist.linux-armv7l/wheel/locust/util copying build/lib/locust/util/deprecation.py -> build/bdist.linux-armv7l/wheel/locust/util copying build/lib/locust/util/load_locustfile.py -> build/bdist.linux-armv7l/wheel/locust/util copying build/lib/locust/util/__init__.py -> build/bdist.linux-armv7l/wheel/locust/util copying build/lib/locust/util/cache.py -> build/bdist.linux-armv7l/wheel/locust/util copying build/lib/locust/util/rounding.py -> build/bdist.linux-armv7l/wheel/locust/util copying build/lib/locust/util/exception_handler.py -> build/bdist.linux-armv7l/wheel/locust/util copying build/lib/locust/util/timespan.py -> build/bdist.linux-armv7l/wheel/locust/util copying build/lib/locust/clients.py -> build/bdist.linux-armv7l/wheel/locust copying build/lib/locust/log.py -> build/bdist.linux-armv7l/wheel/locust copying build/lib/locust/exception.py -> build/bdist.linux-armv7l/wheel/locust creating build/bdist.linux-armv7l/wheel/locust/test copying build/lib/locust/test/test_load_locustfile.py -> build/bdist.linux-armv7l/wheel/locust/test copying build/lib/locust/test/test_stats.py -> build/bdist.linux-armv7l/wheel/locust/test copying build/lib/locust/test/test_parser.py -> build/bdist.linux-armv7l/wheel/locust/test copying build/lib/locust/test/test_tags.py -> build/bdist.linux-armv7l/wheel/locust/test copying build/lib/locust/test/test_locust_class.py -> build/bdist.linux-armv7l/wheel/locust/test copying build/lib/locust/test/test_web.py -> build/bdist.linux-armv7l/wheel/locust/test copying build/lib/locust/test/test_taskratio.py -> build/bdist.linux-armv7l/wheel/locust/test copying build/lib/locust/test/test_env.py -> build/bdist.linux-armv7l/wheel/locust/test copying build/lib/locust/test/test_interruptable_task.py -> build/bdist.linux-armv7l/wheel/locust/test copying build/lib/locust/test/test_util.py -> build/bdist.linux-armv7l/wheel/locust/test copying build/lib/locust/test/fake_module1_for_env_test.py -> build/bdist.linux-armv7l/wheel/locust/test copying build/lib/locust/test/__init__.py -> build/bdist.linux-armv7l/wheel/locust/test copying build/lib/locust/test/test_debugging.py -> build/bdist.linux-armv7l/wheel/locust/test copying build/lib/locust/test/test_old_wait_api.py -> build/bdist.linux-armv7l/wheel/locust/test copying build/lib/locust/test/test_dispatch.py -> build/bdist.linux-armv7l/wheel/locust/test copying build/lib/locust/test/test_sequential_taskset.py -> build/bdist.linux-armv7l/wheel/locust/test copying build/lib/locust/test/test_main.py -> build/bdist.linux-armv7l/wheel/locust/test copying build/lib/locust/test/test_log.py -> build/bdist.linux-armv7l/wheel/locust/test copying build/lib/locust/test/test_runners.py -> build/bdist.linux-armv7l/wheel/locust/test copying build/lib/locust/test/fake_module2_for_env_test.py -> build/bdist.linux-armv7l/wheel/locust/test copying build/lib/locust/test/test_users.py -> build/bdist.linux-armv7l/wheel/locust/test copying build/lib/locust/test/mock_locustfile.py -> build/bdist.linux-armv7l/wheel/locust/test copying build/lib/locust/test/test_http.py -> build/bdist.linux-armv7l/wheel/locust/test copying build/lib/locust/test/test_wait_time.py -> build/bdist.linux-armv7l/wheel/locust/test copying build/lib/locust/test/mock_logging.py -> build/bdist.linux-armv7l/wheel/locust/test copying build/lib/locust/test/test_fasthttp.py -> build/bdist.linux-armv7l/wheel/locust/test copying build/lib/locust/test/test_zmqrpc.py -> build/bdist.linux-armv7l/wheel/locust/test copying build/lib/locust/test/testcases.py -> build/bdist.linux-armv7l/wheel/locust/test copying build/lib/locust/test/util.py -> build/bdist.linux-armv7l/wheel/locust/test copying build/lib/locust/main.py -> build/bdist.linux-armv7l/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-armv7l/wheel/locust-0.0.0.egg-info running install_scripts creating build/bdist.linux-armv7l/wheel/locust-0.0.0.dist-info/WHEEL creating '/build/reproducible-path/locust-2.24.0/.pybuild/cpython3_3.11_locust/.tmp-8rtu8zbr/locust-0.0.0-py3-none-any.whl' and adding 'build/bdist.linux-armv7l/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-armv7l/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:/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 FAILED [ 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 FAILED [ 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 PASSED [ 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 PASSED [ 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 PASSED [ 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 PASSED [ 71%] locust/test/test_runners.py::TestStopTimeout::test_stop_timeout PASSED [ 71%] locust/test/test_runners.py::TestStopTimeout::test_stop_timeout_during_on_start PASSED [ 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 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 PASSED [ 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 PASSED [ 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 =================================== _ TestLargeScale.test_ramp_up_from_0_to_100_000_users_with_50_user_classes_and_1000_workers_and_5000_spawn_rate _ self = def test_ramp_up_from_0_to_100_000_users_with_50_user_classes_and_1000_workers_and_5000_spawn_rate(self): for user_classes in [ self.weighted_user_classes, self.fixed_user_classes_1M, self.fixed_user_classes_10k, self.mixed_users, ]: workers = [WorkerNode(str(i)) for i in range(1000)] target_user_count = 100_000 users_dispatcher = UsersDispatcher(worker_nodes=workers, user_classes=user_classes) users_dispatcher.new_dispatch(target_user_count=target_user_count, spawn_rate=5_000) users_dispatcher._wait_between_dispatch = 0 all_dispatched_users = list(users_dispatcher) tol = 0.2 > self.assertTrue( all( dispatch_iteration_duration <= tol for dispatch_iteration_duration in users_dispatcher.dispatch_iteration_durations ), "One or more dispatch took more than {:.0f}s to compute (max = {}ms)".format( tol * 1000, 1000 * max(users_dispatcher.dispatch_iteration_durations) ), ) E AssertionError: False is not true : One or more dispatch took more than 200s to compute (max = 227.17094099789392ms) locust/test/test_dispatch.py:2096: 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 ______________ TestFastHttpUserClass.test_client_pool_concurrency ______________ self = def test_client_pool_concurrency(self): class MyUser(FastHttpUser): host = "http://127.0.0.1:%i" % self.port @task def t(self): def concurrent_request(url): response = self.client.get(url) assert response.status_code == 200 pool = gevent.pool.Pool() urls = ["/slow?delay=0.2"] * 20 # these urls are all the same, but they could be different for url in urls: pool.spawn(concurrent_request, url) pool.join() user = MyUser(self.environment) before_requests = time.time() user.t() after_requests = time.time() expected_delta = 0.4 # 20 requests with concurrency 10 and response time 0.2 > self.assertAlmostEqual(before_requests + expected_delta, after_requests, delta=0.1) E AssertionError: 1715222576.1063204 != 1715222576.262659 within 0.1 delta (0.15633869171142578 difference) locust/test/test_fasthttp.py:589: 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/tmpj1n6g7s7_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/tmpj_33glk8_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/tmpgcfz84zc_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/tmpq9dm7ser_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_1715222611_3729844_25366.py,/tmp/tmpvso_t29b_locustfile.py', '--legacy-ui', '--web-port', '41235', ...] 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_1715222611_8836176_86881.py', '--legacy-ui', '--web-port', '42673', ...] 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_1715222612_22524_46279.py', '--web-port', '45897', '-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_1715222612_5648568_65161.py', '--web-port', '39259', '--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: 2: from: not found\n/build/reproducible-path/locust-2.24.0/debian/locust: 5: Syntax error: end of file unexpected\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/tmpok6a4bar_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/tmpjiln409c_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/tmpr9qs9_1f_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_1715222614_1548622_16844.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_1715222614_5064478_27569.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/tmpi80d69cc_locustfile.py,/tmp/tmp5kohb297_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/tmpw16ul379_locustfile.py,/tmp/tmpb44vbukz_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/tmpznftibjt'], 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_1715222615_9655204_88330.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_1715222616_2815485_30201.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/tmpqb92xkyg_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_1715222616_985191_29023.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_1715222617_6401105_31445.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: 2: from: not found\n/build/reproducible-path/locust-2.24.0/debian/locust: 5: Syntax error: end of file unexpected\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/tmpy_1nxad0_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_1715222624_7200305_35744.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/tmpp5a_k7dm_locustfile.py,/tmp/tmpb_swv_j8_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 tmpp5a_k7dm_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/tmp1pja1en8_locustfile.py', '--web-port', '56053', '--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/tmpxdp960qq_locustfile.py', '--web-port', '32769', '--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/tmpkawcrwqr', '--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/tmppcvjfzzx', '--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_1715222626_787195_16184.py,/tmp/tmpukeqrt0h_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/tmpr653s770_locustfile.py,/tmp/tmpwygnwg2q_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_1715222627_5828156_36274.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_1715222628_0687711_87667.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: 2: from: not found\n/build/reproducible-path/locust-2.24.0/debian/locust: 5: Syntax error: end of file unexpected\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: 2: from: not found\n/build/reproducible-path/locust-2.24.0/debian/locust: 5: Syntax error: end of file unexpected\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_1715222629_0425906_70069.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/tmp0jscp16s_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_1715222629_7356822_91838.py,/build/reproducible-path/locust-2.24.0/locust/test/mock_locustfile_1715222629_7362154_8973.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/tmpixy47_sb'], 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_1715222630_5002995_78917.py,/tmp/tmpjbi6dzeh_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_1715222630_8560498_26614.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_1715222631_2031996_34953.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_1715222631_5424721_12896.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_1715222631_8925033_79427.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_1715222632_2420156_66389', '--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_1715222632_6274924_27199.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_1715222632_9684002_84010.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_1715222633_3506227_42633.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: 2: from: not found\n/build/reproducible-path/locust-2.24.0/debian/locust: 5: Syntax error: end of file unexpected\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: 2: from: not found\n/build/reproducible-path/locust-2.24.0/debian/locust: 5: Syntax error: end of file unexpected\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_1715222634_6981149_72795.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_1715222635_1761796_7946.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: 2: from: not found\n/build/reproducible-path/locust-2.24.0/debian/locust: 5: Syntax error: end of file unexpected\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_1715222635_7996063_79485.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_1715222636_183201_66656.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_1715222636_5312858_86073.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 ________ 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. 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 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 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 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 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 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 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. ____________ 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 INFO locust.runners:runners.py:342 Shape test stopping ___________ 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: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: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. 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 __________ 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. 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 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:941 The last worker went missing, stopping test. ___________ 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_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 (virt32b_cae0be8bca74460883b61b738d69e139). That's not going to work. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (virt32b_cae0be8bca74460883b61b738d69e139). That's not going to work. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (virt32b_cae0be8bca74460883b61b738d69e139). 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 (virt32b_cae0be8bca74460883b61b738d69e139). 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 (virt32b_cae0be8bca74460883b61b738d69e139). 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 (virt32b_cae0be8bca74460883b61b738d69e139). 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 (virt32b_cae0be8bca74460883b61b738d69e139). 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 (virt32b_cae0be8bca74460883b61b738d69e139). 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 (virt32b_cae0be8bca74460883b61b738d69e139). 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 (virt32b_cae0be8bca74460883b61b738d69e139). 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 (virt32b_cae0be8bca74460883b61b738d69e139). 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 (virt32b_cae0be8bca74460883b61b738d69e139). 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 (virt32b_cae0be8bca74460883b61b738d69e139). 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 (virt32b_cae0be8bca74460883b61b738d69e139). 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 (virt32b_cae0be8bca74460883b61b738d69e139). 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 (virt32b_cae0be8bca74460883b61b738d69e139). 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 (virt32b_cae0be8bca74460883b61b738d69e139). 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 (virt32b_cae0be8bca74460883b61b738d69e139). 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 (virt32b_cae0be8bca74460883b61b738d69e139). 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 (virt32b_cae0be8bca74460883b61b738d69e139). 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 (virt32b_cae0be8bca74460883b61b738d69e139). 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 (virt32b_cae0be8bca74460883b61b738d69e139). 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 (virt32b_cae0be8bca74460883b61b738d69e139). 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 (virt32b_cae0be8bca74460883b61b738d69e139). 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 (virt32b_cae0be8bca74460883b61b738d69e139). 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 (virt32b_cae0be8bca74460883b61b738d69e139). 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 (virt32b_cae0be8bca74460883b61b738d69e139). 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 (virt32b_cae0be8bca74460883b61b738d69e139). 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 (virt32b_cae0be8bca74460883b61b738d69e139). 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 (virt32b_cae0be8bca74460883b61b738d69e139). 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 (virt32b_cae0be8bca74460883b61b738d69e139). 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 (virt32b_cae0be8bca74460883b61b738d69e139). 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 (virt32b_cae0be8bca74460883b61b738d69e139). 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 (virt32b_cae0be8bca74460883b61b738d69e139). 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 (virt32b_cae0be8bca74460883b61b738d69e139). 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 (virt32b_cae0be8bca74460883b61b738d69e139). 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 (virt32b_cae0be8bca74460883b61b738d69e139). 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 (virt32b_cae0be8bca74460883b61b738d69e139). 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 (virt32b_cae0be8bca74460883b61b738d69e139). 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 (virt32b_cae0be8bca74460883b61b738d69e139). 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 (virt32b_cae0be8bca74460883b61b738d69e139). 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 (virt32b_cae0be8bca74460883b61b738d69e139). 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 (virt32b_cae0be8bca74460883b61b738d69e139). 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 (virt32b_cae0be8bca74460883b61b738d69e139). 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 (virt32b_cae0be8bca74460883b61b738d69e139). 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 (virt32b_cae0be8bca74460883b61b738d69e139). 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 (virt32b_cae0be8bca74460883b61b738d69e139). 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 (virt32b_cae0be8bca74460883b61b738d69e139). 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 (virt32b_cae0be8bca74460883b61b738d69e139). 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 (virt32b_cae0be8bca74460883b61b738d69e139). 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 (virt32b_cae0be8bca74460883b61b738d69e139). 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 (virt32b_cae0be8bca74460883b61b738d69e139). 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 (virt32b_cae0be8bca74460883b61b738d69e139). 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 (virt32b_cae0be8bca74460883b61b738d69e139). 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 (virt32b_cae0be8bca74460883b61b738d69e139). 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 (virt32b_cae0be8bca74460883b61b738d69e139). 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 (virt32b_cae0be8bca74460883b61b738d69e139). 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 (virt32b_cae0be8bca74460883b61b738d69e139). 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 (virt32b_cae0be8bca74460883b61b738d69e139). 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 (virt32b_cae0be8bca74460883b61b738d69e139). 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 (virt32b_cae0be8bca74460883b61b738d69e139). 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. =============================== 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: 25 warnings /usr/lib/python3/dist-packages/gevent/os.py:426: DeprecationWarning: This process (pid=15476) 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_dispatch.py::TestLargeScale::test_ramp_up_from_0_to_100_000_users_with_50_user_classes_and_1000_workers_and_5000_spawn_rate FAILED locust/test/test_fasthttp.py::TestFastHttpUserClass::test_client_pool_concurrency 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::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_stop_timeout_with_interrupt_no_reschedule FAILED locust/test/test_stats.py::TestCsvStats::test_stats_history - Connecti... = 87 failed, 461 passed, 1 skipped, 15 deselected, 44 warnings in 642.16s (0:10:42) = 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 FAILED [ 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 FAILED [ 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 PASSED [ 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 PASSED [ 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 PASSED [ 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 PASSED [ 71%] locust/test/test_runners.py::TestStopTimeout::test_stop_timeout FAILED [ 71%] locust/test/test_runners.py::TestStopTimeout::test_stop_timeout_during_on_start PASSED [ 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 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 PASSED [ 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 PASSED [ 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 =================================== _____________________ TestLargeScale.test_distribute_users _____________________ self = def test_distribute_users(self): for user_classes in [self.weighted_user_classes, self.fixed_user_classes_1M, self.mixed_users]: workers = [WorkerNode(str(i)) for i in range(10_000)] target_user_count = 1_000_000 users_dispatcher = UsersDispatcher(worker_nodes=workers, user_classes=user_classes) ts = time.perf_counter() users_on_workers, user_gen, worker_gen, active_users = users_dispatcher._distribute_users( target_user_count=target_user_count ) delta = time.perf_counter() - ts # Because tests are run with coverage, the code will be slower. # We set the pass criterion to 7000ms, but in real life, the # `_distribute_users` method runs faster than this. > self.assertLessEqual(1000 * delta, 7000) E AssertionError: 8108.6197159893345 not less than or equal to 7000 locust/test/test_dispatch.py:2074: AssertionError ______________ TestFastHttpUserClass.test_client_pool_concurrency ______________ self = def test_client_pool_concurrency(self): class MyUser(FastHttpUser): host = "http://127.0.0.1:%i" % self.port @task def t(self): def concurrent_request(url): response = self.client.get(url) assert response.status_code == 200 pool = gevent.pool.Pool() urls = ["/slow?delay=0.2"] * 20 # these urls are all the same, but they could be different for url in urls: pool.spawn(concurrent_request, url) pool.join() user = MyUser(self.environment) before_requests = time.time() user.t() after_requests = time.time() expected_delta = 0.4 # 20 requests with concurrency 10 and response time 0.2 > self.assertAlmostEqual(before_requests + expected_delta, after_requests, delta=0.1) E AssertionError: 1715223223.2322164 != 1715223223.3748965 within 0.1 delta (0.14268016815185547 difference) locust/test/test_fasthttp.py:589: 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/tmpczyd7pa0_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/tmps1sk2n_v_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/tmpetx83a0f_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/tmpnl8z4h_e_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_1715223257_9503403_30597.py,/tmp/tmp_7jtdvl9_locustfile.py', '--legacy-ui', '--web-port', '43791', ...] 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_1715223258_3735437_78584.py', '--legacy-ui', '--web-port', '50679', ...] 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_1715223258_7807212_70593.py', '--web-port', '36611', '-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_1715223259_2907734_70695.py', '--web-port', '33485', '--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: 2: from: not found\n/build/reproducible-path/locust-2.24.0/debian/locust: 5: Syntax error: end of file unexpected\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/tmpdc7okjfl_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/tmp3e150w3j_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/tmpuwz6tocl_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_1715223261_2128725_36634.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_1715223261_548942_65970.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/tmp071i36ha_locustfile.py,/tmp/tmphrn0q8d8_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/tmp6x7nvfn__locustfile.py,/tmp/tmpnkkcxvzr_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/tmp8m0rimwx'], 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_1715223263_1692874_20994.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_1715223263_6863563_84220.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/tmp4xfs02h8_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_1715223264_5829859_50566.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_1715223265_556739_84899.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: 2: from: not found\n/build/reproducible-path/locust-2.24.0/debian/locust: 5: Syntax error: end of file unexpected\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/tmpbzx4y1o4_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_1715223272_6185796_35513.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/tmpzau7lt_2_locustfile.py,/tmp/tmpgbhhjotq_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 tmpzau7lt_2_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/tmpbne67_8k_locustfile.py', '--web-port', '43283', '--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/tmp3bcyu2w1_locustfile.py', '--web-port', '46815', '--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/tmptreq2p9k', '--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/tmp3bipqo04', '--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_1715223275_135866_19318.py,/tmp/tmppw7fh2_n_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/tmp1kc4fi5g_locustfile.py,/tmp/tmptu3nzcc3_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_1715223275_9786437_1096.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_1715223276_4389343_97280.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: 2: from: not found\n/build/reproducible-path/locust-2.24.0/debian/locust: 5: Syntax error: end of file unexpected\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: 2: from: not found\n/build/reproducible-path/locust-2.24.0/debian/locust: 5: Syntax error: end of file unexpected\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_1715223277_4508202_55468.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/tmpvgl4vkb4_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_1715223278_1159708_14208.py,/build/reproducible-path/locust-2.24.0/locust/test/mock_locustfile_1715223278_1165543_51963.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/tmpf8502e6w'], 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_1715223279_0073245_99834.py,/tmp/tmpbuzhnvh1_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_1715223279_363591_89833.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_1715223279_8876343_25239.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_1715223280_4148421_48689.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_1715223280_794154_78478.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_1715223281_198806_5029', '--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_1715223281_534822_28076.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_1715223282_0461383_53254.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_1715223282_5150387_98129.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: 2: from: not found\n/build/reproducible-path/locust-2.24.0/debian/locust: 5: Syntax error: end of file unexpected\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: 2: from: not found\n/build/reproducible-path/locust-2.24.0/debian/locust: 5: Syntax error: end of file unexpected\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_1715223283_957236_99690.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_1715223284_4227169_249.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: 2: from: not found\n/build/reproducible-path/locust-2.24.0/debian/locust: 5: Syntax error: end of file unexpected\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_1715223285_2679424_34305.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_1715223285_656293_49807.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_1715223285_977787_92862.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 ________ 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. ____________ 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 INFO locust.runners:runners.py:342 Shape test stopping ___________ 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: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: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. 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:941 The last worker went missing, stopping test. ___________ 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_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_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 (virt32b_4056686804de434c9f9c7a29bea53585). That's not going to work. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (virt32b_4056686804de434c9f9c7a29bea53585). That's not going to work. ERROR locust.runners:runners.py:1009 An old (pre 2.0) worker tried to connect (virt32b_4056686804de434c9f9c7a29bea53585). 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 (virt32b_4056686804de434c9f9c7a29bea53585). 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 (virt32b_4056686804de434c9f9c7a29bea53585). 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 (virt32b_4056686804de434c9f9c7a29bea53585). 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 (virt32b_4056686804de434c9f9c7a29bea53585). 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 (virt32b_4056686804de434c9f9c7a29bea53585). 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 (virt32b_4056686804de434c9f9c7a29bea53585). 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 (virt32b_4056686804de434c9f9c7a29bea53585). 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 (virt32b_4056686804de434c9f9c7a29bea53585). 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 (virt32b_4056686804de434c9f9c7a29bea53585). 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 (virt32b_4056686804de434c9f9c7a29bea53585). 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 (virt32b_4056686804de434c9f9c7a29bea53585). 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 (virt32b_4056686804de434c9f9c7a29bea53585). 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 (virt32b_4056686804de434c9f9c7a29bea53585). 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 (virt32b_4056686804de434c9f9c7a29bea53585). 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 (virt32b_4056686804de434c9f9c7a29bea53585). 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 (virt32b_4056686804de434c9f9c7a29bea53585). 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 (virt32b_4056686804de434c9f9c7a29bea53585). 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 (virt32b_4056686804de434c9f9c7a29bea53585). 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 (virt32b_4056686804de434c9f9c7a29bea53585). 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 (virt32b_4056686804de434c9f9c7a29bea53585). 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 (virt32b_4056686804de434c9f9c7a29bea53585). 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 (virt32b_4056686804de434c9f9c7a29bea53585). 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 (virt32b_4056686804de434c9f9c7a29bea53585). 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 (virt32b_4056686804de434c9f9c7a29bea53585). 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 (virt32b_4056686804de434c9f9c7a29bea53585). 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 (virt32b_4056686804de434c9f9c7a29bea53585). 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 (virt32b_4056686804de434c9f9c7a29bea53585). 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 (virt32b_4056686804de434c9f9c7a29bea53585). 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 (virt32b_4056686804de434c9f9c7a29bea53585). 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 (virt32b_4056686804de434c9f9c7a29bea53585). 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 (virt32b_4056686804de434c9f9c7a29bea53585). 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 (virt32b_4056686804de434c9f9c7a29bea53585). 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 (virt32b_4056686804de434c9f9c7a29bea53585). 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 (virt32b_4056686804de434c9f9c7a29bea53585). 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 (virt32b_4056686804de434c9f9c7a29bea53585). 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 (virt32b_4056686804de434c9f9c7a29bea53585). 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 (virt32b_4056686804de434c9f9c7a29bea53585). 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 (virt32b_4056686804de434c9f9c7a29bea53585). 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 (virt32b_4056686804de434c9f9c7a29bea53585). 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 (virt32b_4056686804de434c9f9c7a29bea53585). 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 (virt32b_4056686804de434c9f9c7a29bea53585). 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 (virt32b_4056686804de434c9f9c7a29bea53585). 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 (virt32b_4056686804de434c9f9c7a29bea53585). 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 (virt32b_4056686804de434c9f9c7a29bea53585). 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 (virt32b_4056686804de434c9f9c7a29bea53585). 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 (virt32b_4056686804de434c9f9c7a29bea53585). 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 (virt32b_4056686804de434c9f9c7a29bea53585). 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 (virt32b_4056686804de434c9f9c7a29bea53585). 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 (virt32b_4056686804de434c9f9c7a29bea53585). 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 (virt32b_4056686804de434c9f9c7a29bea53585). 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 (virt32b_4056686804de434c9f9c7a29bea53585). 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 (virt32b_4056686804de434c9f9c7a29bea53585). 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 (virt32b_4056686804de434c9f9c7a29bea53585). 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 (virt32b_4056686804de434c9f9c7a29bea53585). 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 (virt32b_4056686804de434c9f9c7a29bea53585). 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 (virt32b_4056686804de434c9f9c7a29bea53585). 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 (virt32b_4056686804de434c9f9c7a29bea53585). 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 (virt32b_4056686804de434c9f9c7a29bea53585). 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. =============================== 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_dispatch.py::TestLargeScale::test_distribute_users - ... FAILED locust/test/test_fasthttp.py::TestFastHttpUserClass::test_client_pool_concurrency 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::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_stop_timeout - Asse... 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... = 88 failed, 460 passed, 1 skipped, 15 deselected, 2 warnings in 645.33s (0:10:45) = 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_armhf.buildinfo dpkg-genchanges --build=binary -O../locust_2.24.0-1_armhf.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: 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/6492 and its subdirectories I: Current time: Wed May 8 15:03:34 -12 2024 I: pbuilder-time-stamp: 1715223814 Thu May 9 03:04:02 UTC 2024 I: 1st build successful. Starting 2nd build on remote node virt64z-armhf-rb.debian.net. Thu May 9 03:04:02 UTC 2024 I: Preparing to do remote build '2' on virt64z-armhf-rb.debian.net. Thu May 9 03:46:45 UTC 2024 I: Deleting $TMPDIR on virt64z-armhf-rb.debian.net. Thu May 9 03:46:47 UTC 2024 I: locust_2.24.0-1_armhf.changes: Format: 1.8 Date: Wed, 13 Mar 2024 00:41:31 -0400 Source: locust Binary: python3-locust Architecture: all Version: 2.24.0-1 Distribution: unstable Urgency: medium Maintainer: Sandro Tosi Changed-By: Sandro Tosi Description: python3-locust - Developer friendly load testing framework Changes: locust (2.24.0-1) unstable; urgency=medium . * New upstream release * drop patches, no longer needed * debian/control - replace flask-basicauth with flask-login - bump versioned b-d on configargparse to >= 1.5.5 Checksums-Sha1: aed8bfb7002d6bc491066ff16d88ed442d7a8868 7729 locust_2.24.0-1_armhf.buildinfo b3c47e79b47708e1c1c58dda79f5ef67594a3329 1188912 python3-locust_2.24.0-1_all.deb Checksums-Sha256: 35b4e8949d7e356bf045496eac8ba3606c1638f9617e8ec62fea25ecbba7ec5a 7729 locust_2.24.0-1_armhf.buildinfo 4b3957ad87f863803b7acceb6bc4fe69e0de51374e3fd36abecf47a79d30eaa2 1188912 python3-locust_2.24.0-1_all.deb Files: fc9ac72f5f856773e4d87e8398558e92 7729 python optional locust_2.24.0-1_armhf.buildinfo c6389ecaebaefcfb933390ca158b8526 1188912 python optional python3-locust_2.24.0-1_all.deb Thu May 9 03:46:49 UTC 2024 I: diffoscope 265 will be used to compare the two builds: Running as unit: rb-diffoscope-armhf_16-5486.service # Profiling output for: /usr/bin/diffoscope --timeout 7200 --html /srv/reproducible-results/rbuild-debian/r-b-build.Jlc2lR3a/locust_2.24.0-1.diffoscope.html --text /srv/reproducible-results/rbuild-debian/r-b-build.Jlc2lR3a/locust_2.24.0-1.diffoscope.txt --json /srv/reproducible-results/rbuild-debian/r-b-build.Jlc2lR3a/locust_2.24.0-1.diffoscope.json --profile=- /srv/reproducible-results/rbuild-debian/r-b-build.Jlc2lR3a/b1/locust_2.24.0-1_armhf.changes /srv/reproducible-results/rbuild-debian/r-b-build.Jlc2lR3a/b2/locust_2.24.0-1_armhf.changes ## command (total time: 0.000s) 0.000s 1 call cmp (internal) ## has_same_content_as (total time: 0.000s) 0.000s 1 call abc.DotChangesFile ## main (total time: 0.402s) 0.402s 2 calls outputs 0.000s 1 call cleanup ## recognizes (total time: 0.030s) 0.030s 12 calls diffoscope.comparators.binary.FilesystemFile ## specialize (total time: 0.000s) 0.000s 1 call specialize Finished with result: success Main processes terminated with: code=exited/status=0 Service runtime: 743ms CPU time consumed: 742ms Thu May 9 03:46:50 UTC 2024 I: diffoscope 265 found no differences in the changes files, and a .buildinfo file also exists. Thu May 9 03:46:50 UTC 2024 I: locust from trixie built successfully and reproducibly on armhf. Thu May 9 03:46:51 UTC 2024 I: Submitting .buildinfo files to external archives: Thu May 9 03:46:51 UTC 2024 I: Submitting 12K b1/locust_2.24.0-1_armhf.buildinfo.asc Thu May 9 03:46:52 UTC 2024 I: Submitting 12K b2/locust_2.24.0-1_armhf.buildinfo.asc Thu May 9 03:46:53 UTC 2024 I: Done submitting .buildinfo files to http://buildinfo.debian.net/api/submit. Thu May 9 03:46:53 UTC 2024 I: Done submitting .buildinfo files. Thu May 9 03:46:53 UTC 2024 I: Removing signed locust_2.24.0-1_armhf.buildinfo.asc files: removed './b1/locust_2.24.0-1_armhf.buildinfo.asc' removed './b2/locust_2.24.0-1_armhf.buildinfo.asc'