From a1ca220d137cf7b3f79b516980a042ec800a8d91 Mon Sep 17 00:00:00 2001 From: Scott Moser Date: Fri, 9 Feb 2018 17:59:13 -0500 Subject: tools: run-centos: git clone rather than tar. This changes tools/run-centos to collect up your git working directory via 'git' commands rather than just collecting the whole directory. The reason for this is that even a clean tree that has had tox run on it might have up to 400M of data in it. It adds a '--dirty' flag to run-centos to collect up local changes. --- tools/run-centos | 88 ++++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 76 insertions(+), 12 deletions(-) (limited to 'tools/run-centos') diff --git a/tools/run-centos b/tools/run-centos index d58ef3e8..6ac6c11f 100755 --- a/tools/run-centos +++ b/tools/run-centos @@ -23,6 +23,9 @@ Usage: ${0##*/} [ options ] version options: -a | --artifact keep .rpm artifacts + --dirty apply local changes before running tests. + If not provided, a clean checkout of branch is tested. + Inside container, changes are in local-changes.diff. -k | --keep keep container after tests -r | --rpm build .rpm -s | --srpm build .src.rpm @@ -80,25 +83,84 @@ inside() { inject_cloud_init(){ # take current cloud-init git dir and put it inside $name at # ~$user/cloud-init. - local name="$1" user="$2" top_d="" dname="" pstat="" - top_d=$(git rev-parse --show-toplevel) || { - errorrc "Failed to get git top level in $PWD"; + local name="$1" user="$2" dirty="$3" + local changes="" top_d="" dname="cloud-init" pstat="" + local gitdir="" commitish="" + gitdir=$(git rev-parse --git-dir) || { + errorrc "Failed to get git dir in $PWD"; return } - dname=$(basename "${top_d}") || return - debug 1 "collecting ${top_d} ($dname) into user $user in $name." - tar -C "${top_d}/.." -cpf - "$dname" | + local t=${gitdir%/*} + case "$t" in + */worktrees) + if [ -f "${t%worktrees}/config" ]; then + gitdir="${t%worktrees}" + fi + esac + + # attempt to get branch name. + commitish=$(git rev-parse --abbrev-ref HEAD) || { + errorrc "Failed git rev-parse --abbrev-ref HEAD" + return + } + if [ "$commitish" = "HEAD" ]; then + # detached head + commitish=$(git rev-parse HEAD) || { + errorrc "failed git rev-parse HEAD" + return + } + fi + + local local_changes=false + if ! git diff --quiet "$commitish"; then + # there are local changes not committed. + local_changes=true + if [ "$dirty" = "false" ]; then + error "WARNING: You had uncommitted changes. Those changes will " + error "be put into 'local-changes.diff' inside the container. " + error "To test these changes you must pass --dirty." + fi + fi + + debug 1 "collecting ${gitdir} ($dname) into user $user in $name." + tar -C "${gitdir}" -cpf - . | inside_as "$name" "$user" sh -ec ' dname=$1 + commitish=$2 rm -Rf "$dname" + mkdir -p $dname/.git + cd $dname/.git tar -xpf - - [ "$dname" = "cloud-init" ] || mv "$dname" cloud-init' \ - extract "$dname" + cd .. + git config core.bare false + out=$(git checkout $commitish 2>&1) || + { echo "failed git checkout $commitish: $out" 1>&2; exit 1; } + out=$(git checkout . 2>&1) || + { echo "failed git checkout .: $out" 1>&2; exit 1; } + ' extract "$dname" "$commitish" [ "${PIPESTATUS[*]}" = "0 0" ] || { - error "Failed to push tarball of '$top_d' into $name" \ + error "Failed to push tarball of '$gitdir' into $name" \ " for user $user (dname=$dname)" return 1 } + + echo "local_changes=$local_changes dirty=$dirty" + if [ "$local_changes" = "true" ]; then + git diff "$commitish" | + inside_as "$name" "$user" sh -exc ' + cd "$1" + if [ "$2" = "true" ]; then + git apply + else + cat > local-changes.diff + fi + ' insert_changes "$dname" "$dirty" + [ "${PIPESTATUS[*]}" = "0 0" ] || { + error "Failed to apply local changes." + return 1 + } + fi + return 0 } @@ -179,7 +241,7 @@ delete_container() { main() { local short_opts="ahkrsuv" - local long_opts="artifact,help,keep,rpm,srpm,unittest,verbose" + local long_opts="artifact,dirty,help,keep,rpm,srpm,unittest,verbose" local getopt_out="" getopt_out=$(getopt --name "${0##*/}" \ --options "${short_opts}" --long "${long_opts}" -- "$@") && @@ -188,11 +250,13 @@ main() { local cur="" next="" local artifact="" keep="" rpm="" srpm="" unittest="" version="" + local dirty=false while [ $# -ne 0 ]; do cur="${1:-}"; next="${2:-}"; case "$cur" in -a|--artifact) artifact=1;; + --dirty) dirty=true;; -h|--help) Usage ; exit 0;; -k|--keep) KEEP=true;; -r|--rpm) rpm=1;; @@ -231,7 +295,7 @@ main() { inside "$name" useradd "$user" debug 1 "inserting cloud-init" - inject_cloud_init "$name" "$user" || { + inject_cloud_init "$name" "$user" "$dirty" || { errorrc "FAIL: injecting cloud-init into $name failed." return } @@ -244,7 +308,7 @@ main() { local errors=0 inside_as_cd "$name" "$user" "$cdir" \ - sh -ec "git checkout .; git status" || + sh -ec "git status" || { errorrc "git checkout failed."; errors=$(($errors+1)); } if [ -n "$unittest" ]; then -- cgit v1.2.3 From 754f54037aca0f604b8b57ab71b30dad5e5066cf Mon Sep 17 00:00:00 2001 From: Scott Moser Date: Mon, 12 Feb 2018 13:54:50 -0700 Subject: tests: run nosetests in cloudinit/ directory, fix py26 fallout. When we moved some tests to live under cloudinit/ we inadvertantly failed to change all things that would run nose to include that directory. This changes all the 'nose' invocations to consistently run with tests/unittests and cloudinit/. Also, it works around, more correctly this time, a python2.6-ism with the following code: with assertRaises(SystemExit) as cm: sys.exit(2) --- cloudinit/cmd/tests/test_clean.py | 3 ++- cloudinit/cmd/tests/test_status.py | 3 ++- cloudinit/tests/helpers.py | 20 +++++++++----------- tests/unittests/test_handler/test_schema.py | 12 +++++++----- tools/run-centos | 3 ++- tox.ini | 6 +++--- 6 files changed, 25 insertions(+), 22 deletions(-) (limited to 'tools/run-centos') diff --git a/cloudinit/cmd/tests/test_clean.py b/cloudinit/cmd/tests/test_clean.py index 6713af4f..5a3ec3bf 100644 --- a/cloudinit/cmd/tests/test_clean.py +++ b/cloudinit/cmd/tests/test_clean.py @@ -165,10 +165,11 @@ class TestClean(CiTestCase): wrap_and_call( 'cloudinit.cmd.clean', {'Init': {'side_effect': self.init_class}, + 'sys.exit': {'side_effect': self.sys_exit}, 'sys.argv': {'new': ['clean', '--logs']}}, clean.main) - self.assertRaisesCodeEqual(0, context_manager.exception.code) + self.assertEqual(0, context_manager.exception.code) self.assertFalse( os.path.exists(self.log1), 'Unexpected log {0}'.format(self.log1)) diff --git a/cloudinit/cmd/tests/test_status.py b/cloudinit/cmd/tests/test_status.py index 4a5a8c06..37a89936 100644 --- a/cloudinit/cmd/tests/test_status.py +++ b/cloudinit/cmd/tests/test_status.py @@ -380,10 +380,11 @@ class TestStatus(CiTestCase): wrap_and_call( 'cloudinit.cmd.status', {'sys.argv': {'new': ['status']}, + 'sys.exit': {'side_effect': self.sys_exit}, '_is_cloudinit_disabled': (False, ''), 'Init': {'side_effect': self.init_class}}, status.main) - self.assertRaisesCodeEqual(0, context_manager.exception.code) + self.assertEqual(0, context_manager.exception.code) self.assertEqual('status: running\n', m_stdout.getvalue()) # vi: ts=4 expandtab syntax=python diff --git a/cloudinit/tests/helpers.py b/cloudinit/tests/helpers.py index 0080c729..41d9a8ee 100644 --- a/cloudinit/tests/helpers.py +++ b/cloudinit/tests/helpers.py @@ -173,17 +173,15 @@ class CiTestCase(TestCase): dir = self.tmp_dir() return os.path.normpath(os.path.abspath(os.path.join(dir, path))) - def assertRaisesCodeEqual(self, expected, found): - """Handle centos6 having different context manager for assertRaises. - with assertRaises(Exception) as e: - raise Exception("BOO") - - centos6 will have e.exception as an integer. - anything nwere will have it as something with a '.code'""" - if isinstance(found, int): - self.assertEqual(expected, found) - else: - self.assertEqual(expected, found.code) + def sys_exit(self, code): + """Provide a wrapper around sys.exit for python 2.6 + + In 2.6, this code would produce 'cm.exception' with value int(2) + rather than the SystemExit that was raised by sys.exit(2). + with assertRaises(SystemExit) as cm: + sys.exit(2) + """ + raise SystemExit(code) class ResourceUsingTestCase(CiTestCase): diff --git a/tests/unittests/test_handler/test_schema.py b/tests/unittests/test_handler/test_schema.py index 648573f6..df67a0e0 100644 --- a/tests/unittests/test_handler/test_schema.py +++ b/tests/unittests/test_handler/test_schema.py @@ -336,11 +336,13 @@ class MainTest(CiTestCase): def test_main_missing_args(self): """Main exits non-zero and reports an error on missing parameters.""" - with mock.patch('sys.argv', ['mycmd']): - with mock.patch('sys.stderr', new_callable=StringIO) as m_stderr: - with self.assertRaises(SystemExit) as context_manager: - main() - self.assertEqual('1', str(context_manager.exception)) + with mock.patch('sys.exit', side_effect=self.sys_exit): + with mock.patch('sys.argv', ['mycmd']): + with mock.patch('sys.stderr', new_callable=StringIO) as \ + m_stderr: + with self.assertRaises(SystemExit) as context_manager: + main() + self.assertEqual(1, context_manager.exception.code) self.assertEqual( 'Expected either --config-file argument or --doc\n', m_stderr.getvalue()) diff --git a/tools/run-centos b/tools/run-centos index 6ac6c11f..cb241ee5 100755 --- a/tools/run-centos +++ b/tools/run-centos @@ -313,7 +313,8 @@ main() { if [ -n "$unittest" ]; then debug 1 "running unit tests." - inside_as_cd "$name" "$user" "$cdir" nosetests tests/unittests || + inside_as_cd "$name" "$user" "$cdir" \ + nosetests tests/unittests cloudinit || { errorrc "nosetests failed."; errors=$(($errors+1)); } fi diff --git a/tox.ini b/tox.ini index bb74853f..1f990af4 100644 --- a/tox.ini +++ b/tox.ini @@ -45,7 +45,7 @@ deps = -r{toxinidir}/test-requirements.txt [testenv:py26] deps = -r{toxinidir}/test-requirements.txt -commands = nosetests {posargs:tests/unittests} +commands = nosetests {posargs:tests/unittests cloudinit} setenv = LC_ALL = C @@ -83,7 +83,7 @@ deps = [testenv:centos6] basepython = python2.6 -commands = nosetests {posargs:tests/unittests} +commands = nosetests {posargs:tests/unittests cloudinit} deps = # requirements argparse==1.2.1 @@ -98,7 +98,7 @@ deps = [testenv:opensusel42] basepython = python2.7 -commands = nosetests {posargs:tests/unittests} +commands = nosetests {posargs:tests/unittests cloudinit} deps = # requirements argparse==1.3.0 -- cgit v1.2.3