Merge pull request #5 from krallin/tests-in-ci

Run some functional tests in ci/run_build.sh
This commit is contained in:
Thomas Orozco 2015-07-05 14:36:35 +02:00
commit 98311caf52
12 changed files with 156 additions and 14 deletions

View File

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

View File

@ -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

View File

@ -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"

View File

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

View File

@ -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

View File

@ -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()

View File

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

33
test/run_inner_tests.py Executable file
View File

@ -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()

0
test/test.py → test/run_outer_tests.py Normal file → Executable file
View File

View File

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

19
test/subreaper-proxy.py Executable file
View File

@ -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()

View File

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