Compare commits
1 commit
Author | SHA1 | Date | |
---|---|---|---|
|
b2203fd5b1 |
31 changed files with 247 additions and 377 deletions
60
.github/workflows/ci.yaml
vendored
60
.github/workflows/ci.yaml
vendored
|
@ -1,60 +0,0 @@
|
|||
name: CI
|
||||
on: push
|
||||
jobs:
|
||||
build-and-test:
|
||||
runs-on: ubuntu-20.04
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- arch: amd64
|
||||
manylinux_arch: x86_64
|
||||
docker_image: debian:buster
|
||||
|
||||
- arch: arm64
|
||||
manylinux_arch: aarch64
|
||||
docker_image: arm64v8/debian:buster
|
||||
|
||||
- arch: ppc64le
|
||||
manylinux_arch: ppc64le
|
||||
docker_image: ppc64le/debian:buster
|
||||
|
||||
- arch: s390x
|
||||
manylinux_arch: s390x
|
||||
docker_image: s390x/debian:buster
|
||||
|
||||
env:
|
||||
BASE_IMAGE: ${{ matrix.docker_image }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Set up QEMU
|
||||
id: qemu
|
||||
uses: docker/setup-qemu-action@v1
|
||||
if: ${{ matrix.arch != 'amd64' }}
|
||||
with:
|
||||
image: tonistiigi/binfmt:latest
|
||||
|
||||
- name: Build Docker image
|
||||
run: make docker-image
|
||||
|
||||
- name: Run python tests
|
||||
run: docker run --rm -v $(pwd):/mnt:rw dumb-init-build /mnt/ci/docker-python-test
|
||||
|
||||
- name: Build Debian package
|
||||
run: docker run --init --rm -v $(pwd):/mnt:rw dumb-init-build make -C /mnt builddeb
|
||||
|
||||
- name: Test built Debian package
|
||||
# XXX: This uses the clean base image (not the build one) to make
|
||||
# sure it installs in a clean image without any hidden dependencies.
|
||||
run: docker run --rm -v $(pwd):/mnt:rw ${{ matrix.docker_image }} /mnt/ci/docker-deb-test
|
||||
|
||||
- name: Build wheels
|
||||
run: sudo make python-dists-${{ matrix.manylinux_arch }}
|
||||
|
||||
- name: Upload build artifacts
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: ${{ matrix.arch }}
|
||||
path: dist
|
|
@ -1,7 +1,8 @@
|
|||
repos:
|
||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||
rev: v4.4.0
|
||||
rev: v1.2.3
|
||||
hooks:
|
||||
- id: autopep8-wrapper
|
||||
- id: check-added-large-files
|
||||
- id: check-docstring-first
|
||||
- id: check-executables-have-shebangs
|
||||
|
@ -11,33 +12,15 @@ repos:
|
|||
- id: detect-private-key
|
||||
- id: double-quote-string-fixer
|
||||
- id: end-of-file-fixer
|
||||
- id: flake8
|
||||
- id: name-tests-test
|
||||
- id: requirements-txt-fixer
|
||||
- id: trailing-whitespace
|
||||
- repo: https://github.com/pre-commit/mirrors-autopep8
|
||||
rev: v2.0.0
|
||||
hooks:
|
||||
- id: autopep8
|
||||
- repo: https://github.com/pycqa/flake8
|
||||
rev: 6.0.0
|
||||
hooks:
|
||||
- id: flake8
|
||||
- repo: https://github.com/asottile/reorder_python_imports
|
||||
rev: v3.9.0
|
||||
rev: v1.0.1
|
||||
hooks:
|
||||
- id: reorder-python-imports
|
||||
args: ['--py3-plus']
|
||||
- repo: https://github.com/Lucas-C/pre-commit-hooks
|
||||
rev: v1.3.1
|
||||
rev: v1.1.5
|
||||
hooks:
|
||||
- id: remove-tabs
|
||||
- repo: https://github.com/asottile/pyupgrade
|
||||
rev: v3.3.0
|
||||
hooks:
|
||||
- id: pyupgrade
|
||||
args: ['--py3-plus']
|
||||
- repo: https://github.com/asottile/add-trailing-comma
|
||||
rev: v2.3.0
|
||||
hooks:
|
||||
- id: add-trailing-comma
|
||||
args: ['--py36-plus']
|
||||
|
|
19
.travis.yml
Normal file
19
.travis.yml
Normal file
|
@ -0,0 +1,19 @@
|
|||
language: c
|
||||
services:
|
||||
- docker
|
||||
|
||||
matrix:
|
||||
include:
|
||||
- env: ITEST_TARGET=itest_trusty
|
||||
- env: ITEST_TARGET=itest_xenial
|
||||
- env: ITEST_TARGET=itest_bionic
|
||||
- env: ITEST_TARGET=itest_stretch
|
||||
- env: ITEST_TARGET=itest_tox
|
||||
- os: linux-ppc64le
|
||||
env: ITEST_TARGET=itest_stretch
|
||||
|
||||
script:
|
||||
- make "$ITEST_TARGET"
|
||||
|
||||
after_script:
|
||||
- ci/artifact-upload
|
|
@ -29,11 +29,11 @@ The process to release a new version is:
|
|||
4. Commit the changes and tag the commit like `v1.0.0`.
|
||||
5. `git push --tags origin master`
|
||||
6. Wait for Travis to run, then find and download the binary and Debian
|
||||
packages for all architectures; there will be links printed at the
|
||||
end of the Travis output. Put these into your `dist` directory.
|
||||
packages for both amd64 and ppc64el; there will be links printed at the end
|
||||
of the Travis output. Put these into your `dist` directory.
|
||||
7. Run `make release`
|
||||
8. Run `twine upload --skip-existing dist/*.tar.gz dist/*.whl` to upload the
|
||||
new version to PyPI
|
||||
9. Upload the resulting Debian packages, binaries, and sha256sums file (all
|
||||
inside the `dist` directory) to a new [GitHub
|
||||
9. Upload the resulting Debian package, binary (inside the `dist` directory),
|
||||
and sha256sums file to a new [GitHub
|
||||
release](https://github.com/Yelp/dumb-init/releases)
|
||||
|
|
30
Dockerfile
30
Dockerfile
|
@ -1,28 +1,24 @@
|
|||
ARG BASE_IMAGE=debian:buster
|
||||
FROM $BASE_IMAGE
|
||||
FROM debian:stretch
|
||||
|
||||
LABEL maintainer="Chris Kuehl <ckuehl@yelp.com>"
|
||||
|
||||
# The default mirrors are too flaky to run reliably in CI.
|
||||
RUN sed -E \
|
||||
'/security\.debian/! s@http://[^/]+/@http://mirrors.kernel.org/@' \
|
||||
-i /etc/apt/sources.list
|
||||
|
||||
# Install the bare minimum dependencies necessary for working with Debian
|
||||
# packages. Build dependencies should be added under "Build-Depends" inside
|
||||
# debian/control instead.
|
||||
RUN : \
|
||||
&& apt-get update \
|
||||
&& DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
|
||||
RUN DEBIAN_FRONTEND=noninteractive apt-get update && \
|
||||
apt-get install -y --no-install-recommends \
|
||||
build-essential \
|
||||
devscripts \
|
||||
equivs \
|
||||
lintian \
|
||||
python3-distutils \
|
||||
python3-setuptools \
|
||||
python3-pip \
|
||||
&& apt-get clean \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
WORKDIR /tmp/mnt
|
||||
&& rm -rf /var/lib/apt/lists/* && apt-get clean
|
||||
WORKDIR /mnt
|
||||
|
||||
COPY debian/control /control
|
||||
RUN : \
|
||||
&& apt-get update \
|
||||
&& mk-build-deps --install --tool 'apt-get -y --no-install-recommends' /control \
|
||||
&& apt-get clean \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
ENTRYPOINT apt-get update && \
|
||||
mk-build-deps -i --tool 'apt-get --no-install-recommends -y' && \
|
||||
make builddeb
|
||||
|
|
41
Makefile
41
Makefile
|
@ -26,21 +26,18 @@ clean-tox:
|
|||
.PHONY: release
|
||||
release: python-dists
|
||||
cd dist && \
|
||||
sha256sum --binary dumb-init_$(VERSION)_amd64.deb dumb-init_$(VERSION)_x86_64 dumb-init_$(VERSION)_ppc64el.deb dumb-init_$(VERSION)_ppc64le dumb-init_$(VERSION)_s390x.deb dumb-init_$(VERSION)_s390x dumb-init_$(VERSION)_arm64.deb dumb-init_$(VERSION)_aarch64 \
|
||||
sha256sum --binary dumb-init_$(VERSION)_amd64.deb dumb-init_$(VERSION)_amd64 dumb-init_$(VERSION)_ppc64el.deb dumb-init_$(VERSION)_ppc64el \
|
||||
> sha256sums
|
||||
|
||||
.PHONY: python-dists
|
||||
python-dists: python-dists-x86_64 python-dists-aarch64 python-dists-ppc64le python-dists-s390x
|
||||
|
||||
.PHONY: python-dists-%
|
||||
python-dists-%: VERSION.h
|
||||
python-dists: VERSION.h
|
||||
python setup.py sdist
|
||||
docker run \
|
||||
--user $$(id -u):$$(id -g) \
|
||||
-v `pwd`/dist:/dist:rw \
|
||||
quay.io/pypa/manylinux2014_$*:latest \
|
||||
-v $(PWD)/dist:/dist:rw \
|
||||
quay.io/pypa/manylinux1_x86_64:latest \
|
||||
bash -exc ' \
|
||||
/opt/python/cp38-cp38/bin/pip wheel --wheel-dir /tmp /dist/*.tar.gz && \
|
||||
/opt/python/cp35-cp35m/bin/pip wheel --wheel-dir /tmp /dist/*.tar.gz && \
|
||||
auditwheel repair --wheel-dir /dist /tmp/*.whl --wheel-dir /dist \
|
||||
'
|
||||
|
||||
|
@ -52,16 +49,16 @@ builddeb:
|
|||
# Extract the built binary from the Debian package
|
||||
dpkg-deb --fsys-tarfile dist/dumb-init_$(VERSION)_$(shell dpkg --print-architecture).deb | \
|
||||
tar -C dist --strip=3 -xvf - ./usr/bin/dumb-init
|
||||
mv dist/dumb-init dist/dumb-init_$(VERSION)_$(shell uname -m)
|
||||
mv dist/dumb-init dist/dumb-init_$(VERSION)_$(shell dpkg --print-architecture)
|
||||
|
||||
.PHONY: builddeb-docker
|
||||
builddeb-docker: docker-image
|
||||
mkdir -p dist
|
||||
docker run --init --user $$(id -u):$$(id -g) -v $(PWD):/tmp/mnt dumb-init-build make builddeb
|
||||
docker run -v $(PWD):/mnt dumb-init-build
|
||||
|
||||
.PHONY: docker-image
|
||||
docker-image:
|
||||
docker build $(if $(BASE_IMAGE),--build-arg BASE_IMAGE=$(BASE_IMAGE)) -t dumb-init-build .
|
||||
docker build -t dumb-init-build .
|
||||
|
||||
.PHONY: test
|
||||
test:
|
||||
|
@ -71,3 +68,25 @@ test:
|
|||
.PHONY: install-hooks
|
||||
install-hooks:
|
||||
tox -e pre-commit -- install -f --install-hooks
|
||||
|
||||
ITEST_TARGETS = itest_trusty itest_xenial itest_bionic itest_stretch
|
||||
|
||||
.PHONY: itest $(ITEST_TARGETS)
|
||||
itest: $(ITEST_TARGETS)
|
||||
|
||||
itest_trusty: _itest-ubuntu-trusty
|
||||
itest_xenial: _itest-ubuntu-xenial
|
||||
itest_bionic: _itest-ubuntu-bionic
|
||||
itest_stretch: _itest-debian-stretch
|
||||
|
||||
itest_tox:
|
||||
$(DOCKER_RUN_TEST) ubuntu:bionic /mnt/ci/docker-tox-test
|
||||
|
||||
_itest-%: _itest_deb-% _itest_python-%
|
||||
@true
|
||||
|
||||
_itest_python-%:
|
||||
$(DOCKER_RUN_TEST) $(shell sed 's/-/:/' <<< "$*") /mnt/ci/docker-python-test
|
||||
|
||||
_itest_deb-%: builddeb-docker
|
||||
$(DOCKER_RUN_TEST) $(shell sed 's/-/:/' <<< "$*") /mnt/ci/docker-deb-test
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
dumb-init
|
||||
========
|
||||
|
||||
[![Travis CI](https://travis-ci.org/Yelp/dumb-init.svg?branch=master)](https://travis-ci.org/Yelp/dumb-init/)
|
||||
[![PyPI version](https://badge.fury.io/py/dumb-init.svg)](https://pypi.python.org/pypi/dumb-init)
|
||||
|
||||
|
||||
|
@ -173,7 +174,7 @@ If you don't have an internal apt server, you can use `dpkg -i` to install the
|
|||
One possibility is with the following commands in your Dockerfile:
|
||||
|
||||
```Dockerfile
|
||||
RUN wget https://github.com/Yelp/dumb-init/releases/download/v1.2.5/dumb-init_1.2.5_amd64.deb
|
||||
RUN wget https://github.com/Yelp/dumb-init/releases/download/v1.2.1/dumb-init_1.2.1_amd64.deb
|
||||
RUN dpkg -i dumb-init_*.deb
|
||||
```
|
||||
|
||||
|
@ -184,7 +185,7 @@ Since dumb-init is released as a statically-linked binary, you can usually just
|
|||
plop it into your images. Here's an example of doing that in a Dockerfile:
|
||||
|
||||
```Dockerfile
|
||||
RUN wget -O /usr/local/bin/dumb-init https://github.com/Yelp/dumb-init/releases/download/v1.2.5/dumb-init_1.2.5_x86_64
|
||||
RUN wget -O /usr/local/bin/dumb-init https://github.com/Yelp/dumb-init/releases/download/v1.2.1/dumb-init_1.2.1_amd64
|
||||
RUN chmod +x /usr/local/bin/dumb-init
|
||||
```
|
||||
|
||||
|
|
2
VERSION
2
VERSION
|
@ -1 +1 @@
|
|||
1.2.5
|
||||
1.2.1
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// THIS FILE IS AUTOMATICALLY GENERATED
|
||||
// Run `make VERSION.h` to update it after modifying VERSION.
|
||||
unsigned char VERSION[] = {
|
||||
0x31, 0x2e, 0x32, 0x2e, 0x35, 0x0a
|
||||
0x31, 0x2e, 0x32, 0x2e, 0x31, 0x0a
|
||||
};
|
||||
unsigned int VERSION_len = 6;
|
||||
|
|
18
ci/docker
Normal file
18
ci/docker
Normal file
|
@ -0,0 +1,18 @@
|
|||
# The default mirrors are too flaky to run reliably in CI.
|
||||
sed -E \
|
||||
'/security\.debian/! s@http://[^/]+/@http://mirrors.kernel.org/@' \
|
||||
-i /etc/apt/sources.list
|
||||
|
||||
apt-get update
|
||||
apt-get install -y --no-install-recommends \
|
||||
build-essential \
|
||||
procps \
|
||||
python \
|
||||
python-dev \
|
||||
python-pip \
|
||||
python-setuptools
|
||||
|
||||
cp -r /mnt/ /test
|
||||
cd /test
|
||||
|
||||
# vim: ft=sh
|
|
@ -1,12 +1,10 @@
|
|||
#!/bin/bash -eux
|
||||
set -o pipefail
|
||||
|
||||
apt-get update
|
||||
apt-get -y --no-install-recommends install python3-pip procps
|
||||
. /mnt/ci/docker
|
||||
|
||||
cd /mnt
|
||||
dpkg -i dist/*.deb
|
||||
pip3 install -r requirements-dev.txt
|
||||
pytest tests/
|
||||
pip install -r requirements-dev.txt
|
||||
py.test tests/
|
||||
|
||||
exec dumb-init /mnt/tests/test-zombies
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
#!/bin/bash -eux
|
||||
set -euo pipefail
|
||||
set -o pipefail
|
||||
|
||||
cd /mnt
|
||||
. /mnt/ci/docker
|
||||
|
||||
python3 setup.py clean
|
||||
python3 setup.py sdist
|
||||
pip3 install -vv dist/*.tar.gz
|
||||
pip3 install -r requirements-dev.txt
|
||||
pytest-3 -vv tests/
|
||||
python setup.py clean
|
||||
python setup.py sdist
|
||||
pip install -vv dist/*.tar.gz
|
||||
pip install -r requirements-dev.txt
|
||||
py.test tests/
|
||||
|
||||
exec dumb-init /mnt/tests/test-zombies
|
||||
exec dumb-init /mnt/tests/test-zombies \
|
||||
|
|
13
ci/docker-tox-test
Executable file
13
ci/docker-tox-test
Executable file
|
@ -0,0 +1,13 @@
|
|||
#!/bin/bash -eux
|
||||
set -o pipefail
|
||||
|
||||
. /mnt/ci/docker
|
||||
|
||||
apt-get update
|
||||
apt-get install -y --no-install-recommends \
|
||||
git \
|
||||
python2.7-dev \
|
||||
python3.6-dev \
|
||||
tox
|
||||
|
||||
tox
|
43
debian/changelog
vendored
43
debian/changelog
vendored
|
@ -1,46 +1,3 @@
|
|||
dumb-init (1.2.5) unstable; urgency=medium
|
||||
|
||||
* Change the working directory in the parent process to "/" after forking.
|
||||
|
||||
https://github.com/Yelp/dumb-init/pull/210
|
||||
|
||||
Thanks to @Villemoes for the patch!
|
||||
|
||||
-- Chris Kuehl <ckuehl@yelp.com> Thu, 10 Dec 2020 10:54:47 -0800
|
||||
|
||||
dumb-init (1.2.4) unstable; urgency=medium
|
||||
|
||||
* Actually fix the bug that can cause `--help` or `--version` to crash in
|
||||
some scenarios.
|
||||
|
||||
https://github.com/Yelp/dumb-init/pull/215
|
||||
|
||||
Thanks to @suve for the patch!
|
||||
|
||||
-- Chris Kuehl <ckuehl@yelp.com> Mon, 07 Dec 2020 11:58:06 -0800
|
||||
|
||||
dumb-init (1.2.3) unstable; urgency=medium
|
||||
|
||||
* Fix a bug that can cause `--help` or `--version` to crash in some
|
||||
scenarios.
|
||||
|
||||
https://github.com/Yelp/dumb-init/pull/213
|
||||
|
||||
Thanks to @suve for the patch!
|
||||
|
||||
-- Chris Kuehl <ckuehl@yelp.com> Wed, 02 Dec 2020 10:43:02 -0800
|
||||
|
||||
dumb-init (1.2.2) unstable; urgency=medium
|
||||
|
||||
* Fix a race condition which can cause the child to receive SIGHUP and
|
||||
SIGCONT very shortly after start (#174).
|
||||
|
||||
In general this was very rare, but some environments (especially some
|
||||
container and virtualization environments) appear to encounter it at a
|
||||
much higher rate, possibly due to scheduler quirks.
|
||||
|
||||
-- Chris Kuehl <ckuehl@yelp.com> Wed, 01 Aug 2018 16:36:22 -0700
|
||||
|
||||
dumb-init (1.2.1) unstable; urgency=medium
|
||||
|
||||
* Fix verbose debug logging for ignored signals.
|
||||
|
|
6
debian/control
vendored
6
debian/control
vendored
|
@ -2,14 +2,16 @@ Source: dumb-init
|
|||
Section: utils
|
||||
Priority: extra
|
||||
Maintainer: Chris Kuehl <ckuehl@yelp.com>
|
||||
Uploaders: Kent Wills <rkwills@yelp.com>
|
||||
Build-Depends:
|
||||
debhelper (>= 9),
|
||||
help2man,
|
||||
musl-tools,
|
||||
## Tests:
|
||||
procps,
|
||||
python3,
|
||||
python3-pytest,
|
||||
python,
|
||||
python-mock,
|
||||
python-pytest,
|
||||
Standards-Version: 3.9.7
|
||||
Homepage: https://github.com/Yelp/dumb-init
|
||||
Vcs-Browser: https://github.com/Yelp/dumb-init
|
||||
|
|
2
debian/rules
vendored
2
debian/rules
vendored
|
@ -31,4 +31,4 @@ override_dh_builddeb:
|
|||
override_dh_auto_test:
|
||||
find . -name '*.pyc' -delete
|
||||
find . -name '__pycache__' -delete
|
||||
PATH=.:$$PATH timeout --signal=KILL 60 pytest-3 -vv tests/
|
||||
PATH=.:$$PATH timeout --signal=KILL 60 py.test -vv tests/
|
||||
|
|
19
dumb-init.c
19
dumb-init.c
|
@ -94,7 +94,7 @@ void handle_signal(int signum) {
|
|||
DEBUG("Received signal %d.\n", signum);
|
||||
|
||||
if (signal_temporary_ignores[signum] == 1) {
|
||||
DEBUG("Ignoring tty hand-off signal %d.\n", signum);
|
||||
DEBUG("Ignoring signal %d during its first receive.\n", signum);
|
||||
signal_temporary_ignores[signum] = 0;
|
||||
} else if (signum == SIGCHLD) {
|
||||
int status, exit_status;
|
||||
|
@ -126,7 +126,7 @@ void handle_signal(int signum) {
|
|||
|
||||
void print_help(char *argv[]) {
|
||||
fprintf(stderr,
|
||||
"dumb-init v%.*s"
|
||||
"dumb-init v%s"
|
||||
"Usage: %s [option] command [[arg] ...]\n"
|
||||
"\n"
|
||||
"dumb-init is a simple process supervisor that forwards signals to children.\n"
|
||||
|
@ -144,7 +144,7 @@ void print_help(char *argv[]) {
|
|||
" -V, --version Print the current version and exit.\n"
|
||||
"\n"
|
||||
"Full help is available online at https://github.com/Yelp/dumb-init\n",
|
||||
VERSION_len, VERSION,
|
||||
VERSION,
|
||||
argv[0]
|
||||
);
|
||||
}
|
||||
|
@ -175,9 +175,8 @@ void parse_rewrite_signum(char *arg) {
|
|||
}
|
||||
|
||||
void set_rewrite_to_sigstop_if_not_defined(int signum) {
|
||||
if (signal_rewrite[signum] == -1) {
|
||||
if (signal_rewrite[signum] == -1)
|
||||
signal_rewrite[signum] = SIGSTOP;
|
||||
}
|
||||
}
|
||||
|
||||
char **parse_command(int argc, char *argv[]) {
|
||||
|
@ -199,7 +198,7 @@ char **parse_command(int argc, char *argv[]) {
|
|||
debug = 1;
|
||||
break;
|
||||
case 'V':
|
||||
fprintf(stderr, "dumb-init v%.*s", VERSION_len, VERSION);
|
||||
fprintf(stderr, "dumb-init v%s", VERSION);
|
||||
exit(0);
|
||||
case 'c':
|
||||
use_setsid = 0;
|
||||
|
@ -256,9 +255,8 @@ int main(int argc, char *argv[]) {
|
|||
sigprocmask(SIG_BLOCK, &all_signals, NULL);
|
||||
|
||||
int i = 0;
|
||||
for (i = 1; i <= MAXSIG; i++) {
|
||||
for (i = 1; i <= MAXSIG; i++)
|
||||
signal(i, dummy);
|
||||
}
|
||||
|
||||
/*
|
||||
* Detach dumb-init from controlling tty, so that the child's session can
|
||||
|
@ -326,11 +324,6 @@ int main(int argc, char *argv[]) {
|
|||
} else {
|
||||
/* parent */
|
||||
DEBUG("Child spawned with PID %d.\n", child_pid);
|
||||
if (chdir("/") == -1) {
|
||||
DEBUG("Unable to chdir(\"/\") (errno=%d %s)\n",
|
||||
errno,
|
||||
strerror(errno));
|
||||
}
|
||||
for (;;) {
|
||||
int signum;
|
||||
sigwait(&all_signals, &signum);
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
[pytest]
|
||||
timeout = 20
|
||||
timeout = 5
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
mock
|
||||
pre-commit>=0.5.0
|
||||
pytest
|
||||
# TODO: This pin is to work around an issue where the system pytest is too old.
|
||||
# We should fix this by not depending on the system pytest/python packages at
|
||||
# some point.
|
||||
pytest-timeout<2.0.0
|
||||
pytest-timeout
|
||||
|
|
8
setup.py
8
setup.py
|
@ -1,9 +1,11 @@
|
|||
from __future__ import print_function
|
||||
|
||||
import os.path
|
||||
import subprocess
|
||||
import tempfile
|
||||
|
||||
from distutils.command.build import build as orig_build
|
||||
from distutils.core import Command
|
||||
|
||||
from setuptools import Distribution
|
||||
from setuptools import Extension
|
||||
from setuptools import setup
|
||||
|
@ -56,8 +58,7 @@ class install_cexe(Command):
|
|||
# this initializes attributes based on other commands' attributes
|
||||
self.set_undefined_options('build', ('build_scripts', 'build_dir'))
|
||||
self.set_undefined_options(
|
||||
'install', ('install_scripts', 'install_dir'),
|
||||
)
|
||||
'install', ('install_scripts', 'install_dir'))
|
||||
|
||||
def run(self):
|
||||
|
||||
|
@ -123,7 +124,6 @@ setup(
|
|||
author='Yelp',
|
||||
url='https://github.com/Yelp/dumb-init/',
|
||||
platforms='linux',
|
||||
packages=[],
|
||||
c_executables=[Extension('dumb-init', ['dumb-init.c'])],
|
||||
cmdclass={
|
||||
'bdist_wheel': bdist_wheel,
|
||||
|
|
|
@ -8,6 +8,9 @@ from contextlib import contextmanager
|
|||
from subprocess import PIPE
|
||||
from subprocess import Popen
|
||||
|
||||
from py._path.local import LocalPath
|
||||
|
||||
|
||||
# these signals cause dumb-init to suspend itself
|
||||
SUSPEND_SIGNALS = frozenset([
|
||||
signal.SIGTSTP,
|
||||
|
@ -17,8 +20,8 @@ SUSPEND_SIGNALS = frozenset([
|
|||
|
||||
NORMAL_SIGNALS = frozenset(
|
||||
set(range(1, 32)) -
|
||||
{signal.SIGKILL, signal.SIGSTOP, signal.SIGCHLD} -
|
||||
SUSPEND_SIGNALS,
|
||||
set([signal.SIGKILL, signal.SIGSTOP, signal.SIGCHLD]) -
|
||||
SUSPEND_SIGNALS
|
||||
)
|
||||
|
||||
|
||||
|
@ -34,7 +37,7 @@ def print_signals(args=()):
|
|||
stdout=PIPE,
|
||||
)
|
||||
line = proc.stdout.readline()
|
||||
m = re.match(b'^ready \\(pid: ([0-9]+)\\)\n$', line)
|
||||
m = re.match(b'^ready \(pid: ([0-9]+)\)\n$', line)
|
||||
assert m, line
|
||||
|
||||
yield proc, m.group(1).decode('ascii')
|
||||
|
@ -46,25 +49,15 @@ def print_signals(args=()):
|
|||
def child_pids(pid):
|
||||
"""Return a list of direct child PIDs for the given PID."""
|
||||
children = set()
|
||||
for p in os.listdir('/proc'):
|
||||
for p in LocalPath('/proc').listdir():
|
||||
try:
|
||||
with open(os.path.join('/proc', p, 'stat')) as f:
|
||||
stat = f.read()
|
||||
m = re.match(
|
||||
r'^\d+ \(.+?\) '
|
||||
# This field, state, is normally a single letter, but can be
|
||||
# "0" if there are some unusual security settings that prevent
|
||||
# reading the process state (happens under GitHub Actions with
|
||||
# QEMU for some reason).
|
||||
'[0a-zA-Z] '
|
||||
r'(\d+) ',
|
||||
stat,
|
||||
)
|
||||
stat = open(p.join('stat').strpath).read()
|
||||
m = re.match('^\d+ \(.+?\) [a-zA-Z] (\d+) ', stat)
|
||||
assert m, stat
|
||||
ppid = int(m.group(1))
|
||||
if ppid == pid:
|
||||
children.add(int(p))
|
||||
except OSError:
|
||||
children.add(int(p.basename))
|
||||
except IOError:
|
||||
# Happens when the process exits after listing it, or between
|
||||
# opening stat and reading it.
|
||||
pass
|
||||
|
@ -74,23 +67,22 @@ def child_pids(pid):
|
|||
def pid_tree(pid):
|
||||
"""Return a list of all descendant PIDs for the given PID."""
|
||||
children = child_pids(pid)
|
||||
return {
|
||||
return set(
|
||||
pid
|
||||
for child in children
|
||||
for pid in pid_tree(child)
|
||||
} | children
|
||||
) | children
|
||||
|
||||
|
||||
def is_alive(pid):
|
||||
"""Return whether a process is running with the given PID."""
|
||||
return os.path.isdir(os.path.join('/proc', str(pid)))
|
||||
return LocalPath('/proc').join(str(pid)).isdir()
|
||||
|
||||
|
||||
def process_state(pid):
|
||||
"""Return a process' state, such as "stopped" or "running"."""
|
||||
with open(os.path.join('/proc', str(pid), 'status')) as f:
|
||||
status = f.read()
|
||||
m = re.search(r'^State:\s+[A-Z] \(([a-z]+)\)$', status, re.MULTILINE)
|
||||
status = LocalPath('/proc').join(str(pid), 'status').read()
|
||||
m = re.search('^State:\s+[A-Z] \(([a-z]+)\)$', status, re.MULTILINE)
|
||||
return m.group(1)
|
||||
|
||||
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
Since all signals are printed and otherwise ignored, you'll need to send
|
||||
SIGKILL (kill -9) to this process to actually end it.
|
||||
"""
|
||||
from __future__ import print_function
|
||||
|
||||
import os
|
||||
import signal
|
||||
import sys
|
||||
|
@ -11,7 +13,7 @@ import time
|
|||
|
||||
|
||||
CATCHABLE_SIGNALS = frozenset(
|
||||
set(range(1, 32)) - {signal.SIGKILL, signal.SIGSTOP, signal.SIGCHLD},
|
||||
set(range(1, 32)) - set([signal.SIGKILL, signal.SIGSTOP, signal.SIGCHLD])
|
||||
)
|
||||
|
||||
|
||||
|
@ -20,7 +22,7 @@ last_signal = None
|
|||
|
||||
|
||||
def unbuffered_print(line):
|
||||
sys.stdout.write('{}\n'.format(line))
|
||||
sys.stdout.write('{0}\n'.format(line))
|
||||
sys.stdout.flush()
|
||||
|
||||
|
||||
|
@ -32,7 +34,7 @@ if __name__ == '__main__':
|
|||
for signum in CATCHABLE_SIGNALS:
|
||||
signal.signal(signum, print_signal)
|
||||
|
||||
unbuffered_print('ready (pid: {})'.format(os.getpid()))
|
||||
unbuffered_print('ready (pid: {0})'.format(os.getpid()))
|
||||
|
||||
# loop forever just printing signals
|
||||
while True:
|
||||
|
|
|
@ -17,7 +17,7 @@ def spawn_and_kill_pipeline():
|
|||
proc = Popen((
|
||||
'dumb-init',
|
||||
'sh', '-c',
|
||||
"yes 'oh, hi' | tail & yes error | tail >&2",
|
||||
"yes 'oh, hi' | tail & yes error | tail >&2"
|
||||
))
|
||||
|
||||
def assert_living_pids():
|
||||
|
@ -32,7 +32,7 @@ def spawn_and_kill_pipeline():
|
|||
|
||||
|
||||
def living_pids(pids):
|
||||
return {pid for pid in pids if is_alive(pid)}
|
||||
return set(pid for pid in pids if is_alive(pid))
|
||||
|
||||
|
||||
@pytest.mark.usefixtures('both_debug_modes', 'setsid_enabled')
|
||||
|
@ -80,7 +80,7 @@ def spawn_process_which_dies_with_children():
|
|||
# we need to sleep before the shell exits, or dumb-init might send
|
||||
# TERM to print_signals before it has had time to register custom
|
||||
# signal handlers
|
||||
'{python} -m testing.print_signals & sleep 1'.format(
|
||||
'{python} -m testing.print_signals & sleep 0.1'.format(
|
||||
python=sys.executable,
|
||||
),
|
||||
),
|
||||
|
@ -91,7 +91,7 @@ def spawn_process_which_dies_with_children():
|
|||
|
||||
# read a line from print_signals, figure out its pid
|
||||
line = proc.stdout.readline()
|
||||
match = re.match(b'ready \\(pid: ([0-9]+)\\)\n', line)
|
||||
match = re.match(b'ready \(pid: ([0-9]+)\)\n', line)
|
||||
assert match, line
|
||||
child_pid = int(match.group(1))
|
||||
|
||||
|
@ -129,14 +129,12 @@ def test_processes_dont_receive_term_on_exit_if_no_setsid():
|
|||
os.kill(child_pid, signal.SIGKILL)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
'args', [
|
||||
('/doesnotexist',),
|
||||
('--', '/doesnotexist'),
|
||||
('-c', '/doesnotexist'),
|
||||
('--single-child', '--', '/doesnotexist'),
|
||||
],
|
||||
)
|
||||
@pytest.mark.parametrize('args', [
|
||||
('/doesnotexist',),
|
||||
('--', '/doesnotexist'),
|
||||
('-c', '/doesnotexist'),
|
||||
('--single-child', '--', '/doesnotexist'),
|
||||
])
|
||||
@pytest.mark.usefixtures('both_debug_modes', 'both_setsid_modes')
|
||||
def test_fails_nonzero_with_bad_exec(args):
|
||||
"""If dumb-init can't exec as requested, it should exit nonzero."""
|
||||
|
|
|
@ -12,34 +12,12 @@ def current_version():
|
|||
return open('VERSION').read().strip()
|
||||
|
||||
|
||||
def normalize_stderr(stderr):
|
||||
# dumb-init prints out argv[0] in its usage message. This should always be
|
||||
# just "dumb-init" under regular test scenarios here since that is how we
|
||||
# call it, but in CI the use of QEMU causes the argv[0] to be replaced with
|
||||
# the full path.
|
||||
#
|
||||
# This is supposed to be avoidable by:
|
||||
# 1) Setting the "P" flag in the binfmt register:
|
||||
# https://en.wikipedia.org/wiki/Binfmt_misc#Registration
|
||||
# This can be done by setting the QEMU_PRESERVE_PARENT env var when
|
||||
# calling binfmt.
|
||||
#
|
||||
# 2) Setting the "QEMU_ARGV0" env var to empty string for *all*
|
||||
# processes:
|
||||
# https://bugs.launchpad.net/qemu/+bug/1835839
|
||||
#
|
||||
# I can get it working properly in CI outside of Docker, but for some
|
||||
# reason not during Docker builds. This doesn't affect the built executable
|
||||
# so I decided to just punt on it.
|
||||
return re.sub(rb'(^|(?<=\s))[a-z/.]+/dumb-init', b'dumb-init', stderr)
|
||||
|
||||
|
||||
@pytest.mark.usefixtures('both_debug_modes', 'both_setsid_modes')
|
||||
def test_no_arguments_prints_usage():
|
||||
proc = Popen(('dumb-init'), stderr=PIPE)
|
||||
_, stderr = proc.communicate()
|
||||
assert proc.returncode != 0
|
||||
assert normalize_stderr(stderr) == (
|
||||
assert stderr == (
|
||||
b'Usage: dumb-init [option] program [args]\n'
|
||||
b'Try dumb-init --help for full usage.\n'
|
||||
)
|
||||
|
@ -50,7 +28,7 @@ def test_exits_invalid_with_invalid_args():
|
|||
proc = Popen(('dumb-init', '--yolo', '/bin/true'), stderr=PIPE)
|
||||
_, stderr = proc.communicate()
|
||||
assert proc.returncode == 1
|
||||
assert normalize_stderr(stderr) in (
|
||||
assert stderr in (
|
||||
b"dumb-init: unrecognized option '--yolo'\n", # glibc
|
||||
b'dumb-init: unrecognized option: yolo\n', # musl
|
||||
)
|
||||
|
@ -65,7 +43,7 @@ def test_help_message(flag, current_version):
|
|||
proc = Popen(('dumb-init', flag), stderr=PIPE)
|
||||
_, stderr = proc.communicate()
|
||||
assert proc.returncode == 0
|
||||
assert normalize_stderr(stderr) == (
|
||||
assert stderr == (
|
||||
b'dumb-init v' + current_version.encode('ascii') + b'\n'
|
||||
b'Usage: dumb-init [option] command [[arg] ...]\n'
|
||||
b'\n'
|
||||
|
@ -107,15 +85,15 @@ def test_verbose(flag):
|
|||
assert stdout == b'oh, hi\n'
|
||||
|
||||
# child/parent race to print output after the fork(), can't guarantee exact order
|
||||
assert re.search(b'(^|\n)\\[dumb-init\\] setsid complete\\.\n', stderr), stderr # child
|
||||
assert re.search(b'(^|\n)\[dumb-init\] setsid complete\.\n', stderr), stderr # child
|
||||
assert re.search( # parent
|
||||
(
|
||||
'(^|\n)\\[dumb-init\\] Child spawned with PID [0-9]+\\.\n'
|
||||
'(^|\n)\[dumb-init\] Child spawned with PID [0-9]+\.\n'
|
||||
'.*' # child might print here
|
||||
'\\[dumb-init\\] Received signal {signal.SIGCHLD}\\.\n'
|
||||
'\\[dumb-init\\] A child with PID [0-9]+ exited with exit status 0.\n'
|
||||
'\\[dumb-init\\] Forwarded signal 15 to children\\.\n'
|
||||
'\\[dumb-init\\] Child exited with status 0\\. Goodbye\\.\n$'
|
||||
'\[dumb-init\] Received signal {signal.SIGCHLD}\.\n'
|
||||
'\[dumb-init\] A child with PID [0-9]+ exited with exit status 0.\n'
|
||||
'\[dumb-init\] Forwarded signal 15 to children\.\n'
|
||||
'\[dumb-init\] Child exited with status 0\. Goodbye\.\n$'
|
||||
).format(signal=signal).encode('utf8'),
|
||||
stderr,
|
||||
re.DOTALL,
|
||||
|
@ -132,30 +110,28 @@ def test_verbose_and_single_child(flag1, flag2):
|
|||
assert stdout == b'oh, hi\n'
|
||||
assert re.match(
|
||||
(
|
||||
'^\\[dumb-init\\] Child spawned with PID [0-9]+\\.\n'
|
||||
'\\[dumb-init\\] Received signal {signal.SIGCHLD}\\.\n'
|
||||
'\\[dumb-init\\] A child with PID [0-9]+ exited with exit status 0.\n'
|
||||
'\\[dumb-init\\] Forwarded signal 15 to children\\.\n'
|
||||
'\\[dumb-init\\] Child exited with status 0\\. Goodbye\\.\n$'
|
||||
'^\[dumb-init\] Child spawned with PID [0-9]+\.\n'
|
||||
'\[dumb-init\] Received signal {signal.SIGCHLD}\.\n'
|
||||
'\[dumb-init\] A child with PID [0-9]+ exited with exit status 0.\n'
|
||||
'\[dumb-init\] Forwarded signal 15 to children\.\n'
|
||||
'\[dumb-init\] Child exited with status 0\. Goodbye\.\n$'
|
||||
).format(signal=signal).encode('utf8'),
|
||||
stderr,
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
'extra_args', [
|
||||
('-r',),
|
||||
('-r', ''),
|
||||
('-r', 'herp'),
|
||||
('-r', 'herp:derp'),
|
||||
('-r', '15'),
|
||||
('-r', '15::12'),
|
||||
('-r', '15:derp'),
|
||||
('-r', '15:12', '-r'),
|
||||
('-r', '15:12', '-r', '0'),
|
||||
('-r', '15:12', '-r', '1:32'),
|
||||
],
|
||||
)
|
||||
@pytest.mark.parametrize('extra_args', [
|
||||
('-r',),
|
||||
('-r', ''),
|
||||
('-r', 'herp'),
|
||||
('-r', 'herp:derp'),
|
||||
('-r', '15'),
|
||||
('-r', '15::12'),
|
||||
('-r', '15:derp'),
|
||||
('-r', '15:12', '-r'),
|
||||
('-r', '15:12', '-r', '0'),
|
||||
('-r', '15:12', '-r', '1:32'),
|
||||
])
|
||||
@pytest.mark.usefixtures('both_debug_modes', 'both_setsid_modes')
|
||||
def test_rewrite_errors(extra_args):
|
||||
proc = Popen(
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import os
|
||||
from unittest import mock
|
||||
|
||||
import mock
|
||||
import pytest
|
||||
|
||||
|
||||
|
|
|
@ -1,28 +0,0 @@
|
|||
import os
|
||||
import shutil
|
||||
from subprocess import PIPE
|
||||
from subprocess import run
|
||||
|
||||
import pytest
|
||||
|
||||
|
||||
@pytest.mark.usefixtures('both_debug_modes', 'both_setsid_modes')
|
||||
def test_working_directories():
|
||||
"""The child process must start in the working directory in which
|
||||
dumb-init was invoked, but dumb-init itself should not keep a
|
||||
reference to that."""
|
||||
|
||||
# We need absolute path to dumb-init since we pass cwd=/tmp to get
|
||||
# predictable output - so we can't rely on dumb-init being found
|
||||
# in the "." directory.
|
||||
dumb_init = os.path.realpath(shutil.which('dumb-init'))
|
||||
proc = run(
|
||||
(
|
||||
dumb_init,
|
||||
'sh', '-c', 'readlink /proc/$PPID/cwd && readlink /proc/$$/cwd',
|
||||
),
|
||||
cwd='/tmp', stdout=PIPE, stderr=PIPE,
|
||||
)
|
||||
|
||||
assert proc.returncode == 0
|
||||
assert proc.stdout == b'/\n/tmp\n'
|
|
@ -11,19 +11,17 @@ def test_exit_status_regular_exit(exit_status):
|
|||
"""dumb-init should exit with the same exit status as the process that it
|
||||
supervises when that process exits normally.
|
||||
"""
|
||||
proc = Popen(('dumb-init', 'sh', '-c', 'exit {}'.format(exit_status)))
|
||||
proc = Popen(('dumb-init', 'sh', '-c', 'exit {0}'.format(exit_status)))
|
||||
proc.wait()
|
||||
assert proc.returncode == exit_status
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
'signal', [
|
||||
signal.SIGTERM,
|
||||
signal.SIGHUP,
|
||||
signal.SIGQUIT,
|
||||
signal.SIGKILL,
|
||||
],
|
||||
)
|
||||
@pytest.mark.parametrize('signal', [
|
||||
signal.SIGTERM,
|
||||
signal.SIGHUP,
|
||||
signal.SIGQUIT,
|
||||
signal.SIGKILL,
|
||||
])
|
||||
@pytest.mark.usefixtures('both_debug_modes', 'both_setsid_modes')
|
||||
def test_exit_status_terminated_by_signal(signal):
|
||||
"""dumb-init should exit with status 128 + signal when the child process is
|
||||
|
@ -31,10 +29,8 @@ def test_exit_status_terminated_by_signal(signal):
|
|||
"""
|
||||
# We use Python because sh is "dash" on Debian and "bash" on others.
|
||||
# https://github.com/Yelp/dumb-init/issues/115
|
||||
proc = Popen((
|
||||
'dumb-init', sys.executable, '-c', 'import os; os.kill(os.getpid(), {})'.format(
|
||||
signal,
|
||||
),
|
||||
))
|
||||
proc = Popen(('dumb-init', sys.executable, '-c', 'import os; os.kill(os.getpid(), {0})'.format(
|
||||
signal,
|
||||
)))
|
||||
proc.wait()
|
||||
assert proc.returncode == 128 + signal
|
||||
|
|
|
@ -15,54 +15,52 @@ def test_proxies_signals():
|
|||
with print_signals() as (proc, _):
|
||||
for signum in NORMAL_SIGNALS:
|
||||
proc.send_signal(signum)
|
||||
assert proc.stdout.readline() == '{}\n'.format(signum).encode('ascii')
|
||||
assert proc.stdout.readline() == '{0}\n'.format(signum).encode('ascii')
|
||||
|
||||
|
||||
def _rewrite_map_to_args(rewrite_map):
|
||||
return chain.from_iterable(
|
||||
('-r', '{}:{}'.format(src, dst)) for src, dst in rewrite_map.items()
|
||||
('-r', '{0}:{1}'.format(src, dst)) for src, dst in rewrite_map.items()
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
'rewrite_map,sequence,expected', [
|
||||
(
|
||||
{},
|
||||
[signal.SIGTERM, signal.SIGQUIT, signal.SIGCONT, signal.SIGINT],
|
||||
[signal.SIGTERM, signal.SIGQUIT, signal.SIGCONT, signal.SIGINT],
|
||||
),
|
||||
@pytest.mark.parametrize('rewrite_map,sequence,expected', [
|
||||
(
|
||||
{},
|
||||
[signal.SIGTERM, signal.SIGQUIT, signal.SIGCONT, signal.SIGINT],
|
||||
[signal.SIGTERM, signal.SIGQUIT, signal.SIGCONT, signal.SIGINT],
|
||||
),
|
||||
|
||||
(
|
||||
{signal.SIGTERM: signal.SIGINT},
|
||||
[signal.SIGTERM, signal.SIGQUIT, signal.SIGCONT, signal.SIGINT],
|
||||
[signal.SIGINT, signal.SIGQUIT, signal.SIGCONT, signal.SIGINT],
|
||||
),
|
||||
(
|
||||
{signal.SIGTERM: signal.SIGINT},
|
||||
[signal.SIGTERM, signal.SIGQUIT, signal.SIGCONT, signal.SIGINT],
|
||||
[signal.SIGINT, signal.SIGQUIT, signal.SIGCONT, signal.SIGINT],
|
||||
),
|
||||
|
||||
(
|
||||
{
|
||||
signal.SIGTERM: signal.SIGINT,
|
||||
signal.SIGINT: signal.SIGTERM,
|
||||
signal.SIGQUIT: signal.SIGQUIT,
|
||||
},
|
||||
[signal.SIGTERM, signal.SIGQUIT, signal.SIGCONT, signal.SIGINT],
|
||||
[signal.SIGINT, signal.SIGQUIT, signal.SIGCONT, signal.SIGTERM],
|
||||
),
|
||||
(
|
||||
{
|
||||
signal.SIGTERM: signal.SIGINT,
|
||||
signal.SIGINT: signal.SIGTERM,
|
||||
signal.SIGQUIT: signal.SIGQUIT,
|
||||
},
|
||||
[signal.SIGTERM, signal.SIGQUIT, signal.SIGCONT, signal.SIGINT],
|
||||
[signal.SIGINT, signal.SIGQUIT, signal.SIGCONT, signal.SIGTERM],
|
||||
),
|
||||
|
||||
# Lowest possible and highest possible signals.
|
||||
(
|
||||
{1: 31, 31: 1},
|
||||
[1, 31],
|
||||
[31, 1],
|
||||
),
|
||||
],
|
||||
)
|
||||
# Lowest possible and highest possible signals.
|
||||
(
|
||||
{1: 31, 31: 1},
|
||||
[1, 31],
|
||||
[31, 1],
|
||||
),
|
||||
])
|
||||
@pytest.mark.usefixtures('both_debug_modes', 'both_setsid_modes')
|
||||
def test_proxies_signals_with_rewrite(rewrite_map, sequence, expected):
|
||||
"""Ensure dumb-init can rewrite signals."""
|
||||
with print_signals(_rewrite_map_to_args(rewrite_map)) as (proc, _):
|
||||
for send, expect_receive in zip(sequence, expected):
|
||||
proc.send_signal(send)
|
||||
assert proc.stdout.readline() == '{}\n'.format(expect_receive).encode('ascii')
|
||||
assert proc.stdout.readline() == '{0}\n'.format(expect_receive).encode('ascii')
|
||||
|
||||
|
||||
@pytest.mark.usefixtures('both_debug_modes', 'setsid_enabled')
|
||||
|
@ -80,12 +78,12 @@ def test_default_rewrites_can_be_overriden_with_setsid_enabled():
|
|||
assert process_state(proc.pid) in ['running', 'sleeping']
|
||||
proc.send_signal(send)
|
||||
|
||||
assert proc.stdout.readline() == '{}\n'.format(expect_receive).encode('ascii')
|
||||
assert proc.stdout.readline() == '{0}\n'.format(expect_receive).encode('ascii')
|
||||
os.waitpid(proc.pid, os.WUNTRACED)
|
||||
assert process_state(proc.pid) == 'stopped'
|
||||
|
||||
proc.send_signal(signal.SIGCONT)
|
||||
assert proc.stdout.readline() == '{}\n'.format(signal.SIGCONT).encode('ascii')
|
||||
assert proc.stdout.readline() == '{0}\n'.format(signal.SIGCONT).encode('ascii')
|
||||
assert process_state(proc.pid) in ['running', 'sleeping']
|
||||
|
||||
|
||||
|
@ -100,8 +98,8 @@ def test_ignored_signals_are_not_proxied():
|
|||
with print_signals(_rewrite_map_to_args(rewrite_map)) as (proc, _):
|
||||
proc.send_signal(signal.SIGTERM)
|
||||
proc.send_signal(signal.SIGINT)
|
||||
assert proc.stdout.readline() == '{}\n'.format(signal.SIGQUIT).encode('ascii')
|
||||
assert proc.stdout.readline() == '{0}\n'.format(signal.SIGQUIT).encode('ascii')
|
||||
|
||||
proc.send_signal(signal.SIGWINCH)
|
||||
proc.send_signal(signal.SIGHUP)
|
||||
assert proc.stdout.readline() == '{}\n'.format(signal.SIGHUP).encode('ascii')
|
||||
assert proc.stdout.readline() == '{0}\n'.format(signal.SIGHUP).encode('ascii')
|
||||
|
|
|
@ -31,7 +31,7 @@ def test_shell_background_support_setsid():
|
|||
# and then both wake up again
|
||||
proc.send_signal(SIGCONT)
|
||||
assert (
|
||||
proc.stdout.readline() == '{}\n'.format(SIGCONT).encode('ascii')
|
||||
proc.stdout.readline() == '{0}\n'.format(SIGCONT).encode('ascii')
|
||||
)
|
||||
assert process_state(pid) in ['running', 'sleeping']
|
||||
assert process_state(proc.pid) in ['running', 'sleeping']
|
||||
|
@ -46,12 +46,12 @@ def test_shell_background_support_without_setsid():
|
|||
for signum in SUSPEND_SIGNALS:
|
||||
assert process_state(proc.pid) in ['running', 'sleeping']
|
||||
proc.send_signal(signum)
|
||||
assert proc.stdout.readline() == '{}\n'.format(signum).encode('ascii')
|
||||
assert proc.stdout.readline() == '{0}\n'.format(signum).encode('ascii')
|
||||
os.waitpid(proc.pid, os.WUNTRACED)
|
||||
assert process_state(proc.pid) == 'stopped'
|
||||
|
||||
proc.send_signal(SIGCONT)
|
||||
assert (
|
||||
proc.stdout.readline() == '{}\n'.format(SIGCONT).encode('ascii')
|
||||
proc.stdout.readline() == '{0}\n'.format(SIGCONT).encode('ascii')
|
||||
)
|
||||
assert process_state(proc.pid) in ['running', 'sleeping']
|
||||
|
|
|
@ -77,7 +77,7 @@ def test_child_gets_controlling_tty_if_we_had_one():
|
|||
output = readall(sfd)
|
||||
assert os.waitpid(pid, 0) == (pid, 0), output
|
||||
|
||||
m = re.search(b'flags are: \\[\\[([a-zA-Z]+)\\]\\]\n', output)
|
||||
m = re.search(b'flags are: \[\[([a-zA-Z]+)\]\]\n', output)
|
||||
assert m, output
|
||||
|
||||
# "m" is job control
|
||||
|
@ -111,8 +111,8 @@ def test_sighup_sigcont_ignored_if_was_session_leader():
|
|||
|
||||
output = readall(fd).decode('UTF-8')
|
||||
|
||||
assert 'Ignoring tty hand-off signal {}.'.format(signal.SIGHUP) in output
|
||||
assert 'Ignoring tty hand-off signal {}.'.format(signal.SIGCONT) in output
|
||||
assert 'Ignoring signal {} during its first receive.'.format(signal.SIGHUP) in output
|
||||
assert 'Ignoring signal {} during its first receive.'.format(signal.SIGCONT) in output
|
||||
|
||||
assert '[dumb-init] Forwarded signal {} to children.'.format(signal.SIGHUP) in output
|
||||
assert '[dumb-init] Forwarded signal {} to children.'.format(signal.SIGCONT) not in output
|
||||
|
|
7
tox.ini
7
tox.ini
|
@ -1,21 +1,20 @@
|
|||
[tox]
|
||||
envlist = py38,gcov
|
||||
envlist = py27,py36,gcov
|
||||
|
||||
[testenv]
|
||||
deps = -r{toxinidir}/requirements-dev.txt
|
||||
commands =
|
||||
pytest
|
||||
python -m pytest
|
||||
|
||||
[testenv:gcov]
|
||||
skip_install = True
|
||||
basepython = /usr/bin/python3.8
|
||||
commands =
|
||||
{toxinidir}/ci/gcov-build {envbindir}
|
||||
{[testenv]commands}
|
||||
{toxinidir}/ci/gcov-report
|
||||
|
||||
[testenv:pre-commit]
|
||||
basepython = /usr/bin/python3.8
|
||||
basepython = /usr/bin/python3.6
|
||||
commands = pre-commit {posargs:run --all-files}
|
||||
|
||||
[flake8]
|
||||
|
|
Loading…
Reference in a new issue