URL: https://github.com/freeipa/freeipa/pull/618 Author: tiran Title: #618: Tox testing support for client wheel packages Action: synchronized
To pull the PR as Git branch: git remote add ghfreeipa https://github.com/freeipa/freeipa git fetch ghfreeipa pull/618/head:pr618 git checkout pr618
From ec1c53805892f3439409e2d2d0d941124583093c Mon Sep 17 00:00:00 2001 From: Christian Heimes <chei...@redhat.com> Date: Thu, 17 Nov 2016 16:43:17 +0100 Subject: [PATCH] tox testing support for client wheel packages Add tox infrastructure to test client wheel packages workflow: * build client packages * install client packages * ipa-run-tests --ipaclient-unittests under Python 2 and 3 * pylint of client packages under Python 2 and 3 * placeholder packages work as expected Signed-off-by: Christian Heimes <chei...@redhat.com> --- .gitignore | 2 ++ .tox-install.sh | 94 ++++++++++++++++++++++++++++++++++++++++++++++++ Makefile.am | 22 +++++++++--- configure.ac | 1 + freeipa.spec.in | 3 ++ ipatests/conftest.py | 4 ++- pypi/test_placeholder.py | 47 ++++++++++++++++++++++++ tox.ini | 55 ++++++++++++++++++++++++++++ 8 files changed, 222 insertions(+), 6 deletions(-) create mode 100755 .tox-install.sh create mode 100644 pypi/test_placeholder.py create mode 100644 tox.ini diff --git a/.gitignore b/.gitignore index 8941fd8..8b57dbc 100644 --- a/.gitignore +++ b/.gitignore @@ -61,6 +61,8 @@ freeipa2-dev-doc # Root directory /freeipa.spec /dist/ +/.tox/ +/.cache/ /*/dist/ /RELEASE /rpmbuild/ diff --git a/.tox-install.sh b/.tox-install.sh new file mode 100755 index 0000000..8f9d221 --- /dev/null +++ b/.tox-install.sh @@ -0,0 +1,94 @@ +#!/bin/bash +set -ex + +FLAVOR="$1" +ENVPYTHON="$2" +ENVSITEPACKAGESDIR="$3" +# 3...end are package requirements +shift 3 + +TOXINIDIR="$(cd "$(dirname "$0")" && pwd)" + +# sanity checks +if [ ! -x "${ENVPYTHON}" ]; then + echo "${ENVPYTHON}: no such executable" + exit 1 +fi + +if [ ! -d "${ENVSITEPACKAGESDIR}" ]; then + echo "${ENVSITEPACKAGESDIR}: no such directory" + exit 2 +fi + +if [ ! -f "${TOXINIDIR}/tox.ini" ]; then + echo "${TOXINIDIR}: no such directory" + exit 3 +fi + +# https://pip.pypa.io/en/stable/user_guide/#environment-variables +export PIP_CACHE_DIR="${TOXINIDIR}/.tox/cache" +mkdir -p "${PIP_CACHE_DIR}" + +DISTBUNDLE="${TOXINIDIR}/dist/bundle" +mkdir -p "${DISTBUNDLE}" + +DISTPYPI="${TOXINIDIR}/dist/pypi" +mkdir -p "${DISTPYPI}" + +# create configure +pushd "${TOXINIDIR}" +if [ ! -f "configure" ]; then + autoreconf -i -f +fi +# (re)create Makefile +./configure --disable-server +popd + +case $FLAVOR in +wheel_bundle) + # copy pylint plugin + cp "${TOXINIDIR}/pylint_plugins.py" "${ENVSITEPACKAGESDIR}" + + # build packages and bundles + make -C "${TOXINIDIR}" \ + wheel_bundle \ + PYTHON="${ENVPYTHON}" \ + IPA_EXTRA_WHEELS="$*" + + # chdir to prevent local .egg-info from messing up pip + pushd "${ENVSITEPACKAGESDIR}" + + # Install packages with dist/bundle/ as extra source for wheels while ignoring + # upstream Python Package Index. + $ENVPYTHON -m pip install \ + --no-index \ + --disable-pip-version-check \ + --constraint "${TOXINIDIR}/.wheelconstraints" \ + --find-links "${DISTBUNDLE}" \ + $@ + + popd + ;; +pypi_packages) + # build packages and bundles + make -C "${TOXINIDIR}" \ + pypi_packages \ + PYTHON="${ENVPYTHON}" + + # chdir to prevent local .egg-info from messing up pip + pushd "${ENVSITEPACKAGESDIR}" + + # Install packages from dist/pypi + $ENVPYTHON -m pip install \ + --disable-pip-version-check \ + --constraint "${TOXINIDIR}/.wheelconstraints" \ + --find-links "${DISTPYPI}" \ + $@ + + popd + ;; +*) + echo "Unknown install flavor $FLAVOR" + exit 1 + ;; +esac diff --git a/Makefile.am b/Makefile.am index 1989b19..7608dfa 100644 --- a/Makefile.am +++ b/Makefile.am @@ -57,6 +57,7 @@ EXTRA_DIST = .mailmap \ clean-local: rm -rf "$(RPMBUILD)" rm -rf "$(top_builddir)/dist" + rm -rf "$(top_builddir)/.tox" rm -rf "$(top_srcdir)/__pycache__" rm -f "$(top_builddir)"/$(PACKAGE)-*.tar.gz @@ -212,6 +213,7 @@ pylint: $(top_builddir)/ipapython/version.py ipasetup.py -path './freeipa-*' -prune -o \ -path './dist' -prune -o \ -path './pypi' -prune -o \ + -path './.tox' -prune -o \ -name '.*' -o \ -name '*.in' -o \ -name '*~' -o \ @@ -254,6 +256,7 @@ endif # WITH_JSLINT .PHONY: bdist_wheel wheel_bundle wheel_placeholder pypi_packages WHEELDISTDIR = $(top_builddir)/dist/wheels +WHEELPYPIDIR = $(top_builddir)/dist/pypi WHEELBUNDLEDIR = $(top_builddir)/dist/bundle @MK_IFEQ@ ($(IPA_SERVER_WHEELS),1) @@ -273,6 +276,9 @@ $(WHEELDISTDIR): $(WHEELBUNDLEDIR): mkdir -p $(WHEELBUNDLEDIR) +$(WHEELPYPIDIR): + mkdir -p $(WHEELPYPIDIR) + bdist_wheel: $(WHEELDISTDIR) rm -f $(foreach item,$(IPA_WHEEL_PACKAGES) ipatests,$(WHEELDISTDIR)/$(item)-*.whl) export IPA_OMIT_INSTALL=$(IPA_OMIT_INSTALL); \ @@ -291,14 +297,20 @@ wheel_bundle: $(WHEELBUNDLEDIR) bdist_wheel .wheelconstraints --wheel-dir $(WHEELBUNDLEDIR) \ $(IPA_WHEEL_PACKAGES) $(IPA_EXTRA_WHEELS) -wheel_placeholder: $(WHEELDISTDIR) +pypi_packages: $(WHEELPYPIDIR) .wheelconstraints + rm -f $(WHEELPYPIDIR)/* + for dir in $(IPACLIENT_SUBDIRS); do \ + $(MAKE) $(AM_MAKEFLAGS) \ + IPA_OMIT_INSTALL=1 WHEELDISTDIR="$(abspath $(WHEELPYPIDIR))" \ + -C $${dir} bdist_wheel || exit 1; \ + done for dir in $(IPA_PLACEHOLDERS); do \ - $(MAKE) $(AM_MAKEFLAGS) -C $(top_srcdir)/pypi/$${dir} bdist_wheel || exit 1; \ + $(MAKE) $(AM_MAKEFLAGS) \ + IPA_OMIT_INSTALL=1 WHEELDISTDIR="$(abspath $(WHEELPYPIDIR))" \ + -C $(top_srcdir)/pypi/$${dir} bdist_wheel || exit 1; \ done - -pypi_packages: bdist_wheel wheel_placeholder @echo -e "\n\nTo upload packages to PyPI, run:\n" - @echo -e " twine upload $(WHEELDISTDIR)/*-$(VERSION)-py2.py3-none-any.whl\n" + @echo -e " twine upload $(WHEELPYPIDIR)/*-$(VERSION)-py2.py3-none-any.whl\n" .PHONY: strip-po: diff --git a/configure.ac b/configure.ac index 8f8751a..68601de 100644 --- a/configure.ac +++ b/configure.ac @@ -276,6 +276,7 @@ AC_CONFIG_COMMANDS([po/POTFILES.in], -path "./${PACKAGE}-*" -prune -o dnl dist directories -path '*/build' -prune -o dnl Python builds -path '*/dist' -prune -o dnl Python dists + -path './.tox' -prune -o dnl Python tox test -path './conf*' -prune -o dnl generated by configure -name '*.py' -print -o dnl -name '*.c' -print -o dnl diff --git a/freeipa.spec.in b/freeipa.spec.in index 6034f74..fbc67cb 100644 --- a/freeipa.spec.in +++ b/freeipa.spec.in @@ -144,9 +144,12 @@ BuildRequires: python-cffi # %if 0%{?with_wheels} BuildRequires: dbus-glib-devel +BuildRequires: libffi-devel +BuildRequires: python-tox BuildRequires: python2-twine BuildRequires: python2-wheel %if 0%{?with_python3} +BuildRequires: python3-tox BuildRequires: python3-twine BuildRequires: python3-wheel %endif diff --git a/ipatests/conftest.py b/ipatests/conftest.py index 61e889d..a57bf7d 100644 --- a/ipatests/conftest.py +++ b/ipatests/conftest.py @@ -52,7 +52,9 @@ 'ipaserver/build', 'ipatests/build', # install/share/wsgi.py - 'install/share' + 'install/share', + # integration plugin imports from ipaplatform + 'ipatests/pytest_plugins', ] diff --git a/pypi/test_placeholder.py b/pypi/test_placeholder.py new file mode 100644 index 0000000..d17b23a --- /dev/null +++ b/pypi/test_placeholder.py @@ -0,0 +1,47 @@ +#!/usr/bin/env python +# Copyright (C) 2017 FreeIPA Contributors see COPYING for license + +import importlib + +import pkg_resources + +import pytest + +@pytest.mark.parametrize("modname", [ + # placeholder packages raise ImportError + 'ipaplatform', + 'ipaserver', + 'ipatests', + # PyPI packages do not have install subpackage + 'ipaclient.install', + 'ipalib.install', + 'ipapython.install', +]) +def test_fail_import(modname): + try: + importlib.import_module(modname) + except ImportError: + pass + else: + pytest.fail("'import {}' does not fail".format(modname)) + + +@pytest.mark.parametrize("modname", [ + 'ipaclient', + 'ipalib', + 'ipapython', +]) +def test_import(modname): + importlib.import_module(modname) + + +@pytest.mark.parametrize("pkgname", [ + 'ipaclient', + 'ipalib', + 'ipaplatform', + 'ipapython', + 'ipaserver', + 'ipatests', +]) +def test_package_installed(pkgname): + pkg_resources.require(pkgname) diff --git a/tox.ini b/tox.ini new file mode 100644 index 0000000..db551df --- /dev/null +++ b/tox.ini @@ -0,0 +1,55 @@ +[tox] +minversion=2.3.1 +envlist=py27,py35,py36,pylint2,pylint3,pypi +skip_missing_interpreters=true +skipsdist=true + +[testenv] +# always re-create virtual env. A special install helper is used to configure, +# build and install packages. +recreate=True +install_command={toxinidir}/.tox-install.sh wheel_bundle {envpython} {envsitepackagesdir} {packages} +changedir={envdir} +setenv= + HOME={envtmpdir} +deps= + ipaclient + ipatests +commands= + {envbindir}/ipa --help + {envpython} -bb {envbindir}/ipa-run-tests --ipaclient-unittests + +[testenv:pylint2] +basepython=python2.7 +deps= + ipaclient + ipapython[certmonger] + pylint +commands= + {envpython} -m pylint \ + --rcfile={toxinidir}/pylintrc \ + --load-plugins pylint_plugins \ + {envsitepackagesdir}/ipaclient \ + {envsitepackagesdir}/ipalib \ + {envsitepackagesdir}/ipapython + +[testenv:pylint3] +basepython=python3 +deps={[testenv:pylint2]deps} +commands={[testenv:pylint2]commands} + +[testenv:pypi] +recreate=True +install_command={toxinidir}/.tox-install.sh pypi_packages {envpython} {envsitepackagesdir} {packages} +changedir={envdir} +setenv= + HOME={envtmpdir} +deps= + pytest + ipaclient + # placeholder + ipaplatform + ipaserver + ipatests +commands= + {envpython} -m pytest {toxinidir}/pypi/test_placeholder.py
-- Manage your subscription for the Freeipa-devel mailing list: https://www.redhat.com/mailman/listinfo/freeipa-devel Contribute to FreeIPA: http://www.freeipa.org/page/Contribute/Code