Run some functional tests in ci/run_build.sh

Using the child subreaper mechanism, we can actually run
tests inside the CI environment without depending on Docker.

While this does not replace the existing tests, it allows
at least some functional coverage within CI.
pull/5/head
Thomas Orozco 10 years ago
parent 5ed5f227e9
commit 1a863f8366
  1. 4
      .travis.yml
  2. 4
      Dockerfile
  3. 38
      ci/run_build.sh
  4. 2
      dtest.sh
  5. 35
      test/0001-Add-PR_SET_CHILD_SUBREAPER.patch
  6. 27
      test/reaping/stage_1.py
  7. 2
      test/reaping/stage_2.py
  8. 33
      test/run_inner_tests.py
  9. 0
      test/run_outer_tests.py
  10. 2
      test/signals/test.py
  11. 19
      test/subreaper-proxy.py
  12. 4
      tpl/travis.yml.tpl

@ -18,6 +18,10 @@ addons:
- git
- gdb
- valgrind
- python-dev
- libcap-dev
- python-pip
- python-virtualenv
script: ./ci/run_build.sh

@ -1,5 +1,7 @@
FROM ubuntu:precise
RUN apt-get update \
&& apt-get install --no-install-recommends --yes build-essential git gdb valgrind cmake rpm python3 \
&& apt-get install --no-install-recommends --yes build-essential git gdb valgrind cmake rpm python-dev libcap-dev python-pip python-virtualenv \
&& rm -rf /var/lib/apt/lists/*
RUN pip install psutil

@ -3,13 +3,23 @@
set -o errexit
set -o nounset
# Paths
: ${SOURCE_DIR:="."}
: ${DIST_DIR:="${SOURCE_DIR}/dist"}
: ${BUILD_DIR:="/tmp/build"}
# Make those paths absolute, and export them for the Python tests to consume.
export SOURCE_DIR="$(readlink -f "${SOURCE_DIR}")"
export DIST_DIR="$(readlink -f "${DIST_DIR}")"
export BUILD_DIR="$(readlink -f "${BUILD_DIR}")"
# Ensure Python output is not buffered (to make tests output clearer)
export PYTHONUNBUFFERED=1
# Set path to prioritize our utils
export REAL_PATH="${PATH}"
export PATH="$(readlink -f "${SOURCE_DIR}")/ci/util:${PATH}"
export PATH="${SOURCE_DIR}/ci/util:${PATH}"
# Build
cmake -B"${BUILD_DIR}" -H"${SOURCE_DIR}"
@ -46,3 +56,29 @@ for tini in "${BUILD_DIR}/tini" "${BUILD_DIR}/tini-static"; do
dpkg --contents "${DIST_DIR}/tini"*deb
fi
done
# Create virtual environment to run tests
VENV="${BUILD_DIR}/venv"
virtualenv "${VENV}"
# Don't use activate because it does not play nice with nounset
export PATH="${VENV}/bin:${PATH}"
# Install test dependencies
# We need a patched version because Travis only gives us Ubuntu Precise
# (whose Linux headers don't include PR_SET_CHILD_SUBREAPER), but actually
# runs a newer Linux Kernel (because we're actually in Docker) that has the
# PR_SET_CHILD_SUBREAPER prctl call.
pushd /tmp
pip install python-prctl==1.6.1 --download="."
tar -xvf /tmp/python-prctl-1.6.1.tar.gz
cd python-prctl-1.6.1
patch -p1 < "${SOURCE_DIR}/test/0001-Add-PR_SET_CHILD_SUBREAPER.patch"
python setup.py install
popd
pip install psutil
# Run tests
python "${SOURCE_DIR}/test/run_inner_tests.py"

@ -6,4 +6,4 @@ IMG="tini"
docker build -t "${IMG}" .
python test/test.py "${IMG}"
python test/run_outer_tests.py "${IMG}"

@ -0,0 +1,35 @@
From b8c6ccd4575837e3901bbdee7b219ef951dc2065 Mon Sep 17 00:00:00 2001
From: Thomas Orozco <thomas@orozco.fr>
Date: Sun, 28 Jun 2015 15:25:37 +0200
Subject: [PATCH] Add PR_SET_CHILD_SUBREAPER
---
_prctlmodule.c | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/_prctlmodule.c b/_prctlmodule.c
index 14121c3..19ad141 100644
--- a/_prctlmodule.c
+++ b/_prctlmodule.c
@@ -15,6 +15,18 @@
#include <sys/prctl.h>
#include <sys/signal.h>
+/* Our builds run in a Docker environment that has those, but they are
+ * not in the kernel headers. Add them.
+ */
+
+#ifndef PR_SET_CHILD_SUBREAPER
+#define PR_SET_CHILD_SUBREAPER 36
+#endif
+
+#ifndef PR_GET_CHILD_SUBREAPER
+#define PR_GET_CHILD_SUBREAPER 37
+#endif
+
/* New in 2.6.32, but named and implemented inconsistently. The linux
* implementation has two ways of setting the policy to the default, and thus
* needs an extra argument. We ignore the first argument and always call
--
2.4.3

@ -1,25 +1,34 @@
#!/usr/bin/env python3
#!/usr/bin/env python
from __future__ import print_function
import os
import subprocess
import time
import psutil
if __name__ == "__main__":
def main():
p = subprocess.Popen([os.path.join(os.path.dirname(__file__), "stage_2.py")])
p.wait()
# These are the only PIDs that should remain if the system is well-behaved:
# - This process
# - Init
expected_pids = [1, os.getpid()]
# In tests, we assume this process is the direct child of init
this_process = psutil.Process(os.getpid())
init_process = this_process.parent()
print("Reaping test: stage_1 is pid{0}, init is pid{1}".format(this_process.pid, init_process.pid))
# The only child PID that should persist is this one.
expected_pids = [this_process.pid]
print("Expecting pids to remain: {0}".format(", ".join(str(pid) for pid in expected_pids)))
while 1:
pids = [pid for pid in os.listdir('/proc') if pid.isdigit()]
print("Has pids: {0}".format(", ".join(pids)))
if set(int(pid) for pid in pids) == set(expected_pids):
pids = [p.pid for p in init_process.children(recursive=True)]
print("Has pids: {0}".format(", ".join(str(pid) for pid in pids)))
if set(pids) == set(expected_pids):
break
time.sleep(1)
if __name__ == "__main__":
main()

@ -1,4 +1,4 @@
#!/usr/bin/env python3
#!/usr/bin/env python
from __future__ import print_function
import subprocess
import os

@ -0,0 +1,33 @@
#!/usr/bin/env python
#coding:utf-8
import os
import sys
import signal
import subprocess
def main():
src = os.environ["SOURCE_DIR"]
build = os.environ["BUILD_DIR"]
proxy = os.path.join(src, "test", "subreaper-proxy.py")
tini = os.path.join(build, "tini")
# Run the reaping test
print "Running reaping test"
p = subprocess.Popen([proxy, tini, "--", os.path.join(src, "test", "reaping", "stage_1.py")])
ret = p.wait()
assert ret == 0, "Reaping test failed!"
# Run the signals test
for signame in "SIGINT", "SIGTERM":
print "running signal test for: {0}".format(signame)
p = subprocess.Popen([proxy, tini, "--", os.path.join(src, "test", "signals", "test.py")])
sig = getattr(signal, signame)
p.send_signal(sig)
ret = p.wait()
assert ret == - sig, "Signals test failed!"
if __name__ == "__main__":
main()

@ -1,4 +1,4 @@
#!/usr/bin/env python3
#!/usr/bin/env python
import time
if __name__ == "__main__":

@ -0,0 +1,19 @@
#!/usr/bin/env python
#coding:utf-8
import os
import sys
import prctl
def main():
args = sys.argv[1:]
print "subreaper-proxy: running '%s'" % (" ".join(args))
prctl.set_child_subreaper(1)
os.execv(args[0], args)
if __name__ == '__main__':
main()

@ -18,6 +18,10 @@ addons:
- git
- gdb
- valgrind
- python-dev
- libcap-dev
- python-pip
- python-virtualenv
script: ./ci/run_build.sh

Loading…
Cancel
Save