From 40a400e42603aa1b80d9f623bc779799b370c091 Mon Sep 17 00:00:00 2001 From: Scott Moser Date: Wed, 21 Sep 2016 15:45:45 -0400 Subject: subp: add 'update_env' argument In order for a caller to use 'env' argument of subp, they will realistically do: env = os.environ.copy() env['FOO'] = 'BZR' subp(cmd, env=env) This shortens that to be: subp(cmd, update_env={'FOO': 'BZR'}) Add tests, and update growpart tests to use mock when playing with os.environ. --- tests/unittests/test_util.py | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) (limited to 'tests/unittests/test_util.py') diff --git a/tests/unittests/test_util.py b/tests/unittests/test_util.py index d2031f59..30f603cb 100644 --- a/tests/unittests/test_util.py +++ b/tests/unittests/test_util.py @@ -223,8 +223,10 @@ class TestKeyValStrings(helpers.TestCase): class TestGetCmdline(helpers.TestCase): def test_cmdline_reads_debug_env(self): - os.environ['DEBUG_PROC_CMDLINE'] = 'abcd 123' - self.assertEqual(os.environ['DEBUG_PROC_CMDLINE'], util.get_cmdline()) + with mock.patch.dict("os.environ", + values={'DEBUG_PROC_CMDLINE': 'abcd 123'}): + ret = util.get_cmdline() + self.assertEqual("abcd 123", ret) class TestLoadYaml(helpers.TestCase): @@ -516,6 +518,7 @@ class TestSubp(helpers.TestCase): utf8_invalid = b'ab\xaadef' utf8_valid = b'start \xc3\xa9 end' utf8_valid_2 = b'd\xc3\xa9j\xc8\xa7' + printenv = ['bash', '-c', 'for n in "$@"; do echo "$n=${!n}"; done', '--'] def printf_cmd(self, *args): # bash's printf supports \xaa. So does /usr/bin/printf @@ -566,6 +569,29 @@ class TestSubp(helpers.TestCase): self.assertEqual(err, data) self.assertEqual(out, b'') + def test_subp_reads_env(self): + with mock.patch.dict("os.environ", values={'FOO': 'BAR'}): + out, err = util.subp(self.printenv + ['FOO'], capture=True) + self.assertEqual('FOO=BAR', out.splitlines()[0]) + + def test_subp_env_and_update_env(self): + out, err = util.subp( + self.printenv + ['FOO', 'HOME', 'K1', 'K2'], capture=True, + env={'FOO': 'BAR'}, + update_env={'HOME': '/myhome', 'K2': 'V2'}) + self.assertEqual( + ['FOO=BAR', 'HOME=/myhome', 'K1=', 'K2=V2'], out.splitlines()) + + def test_subp_update_env(self): + extra = {'FOO': 'BAR', 'HOME': '/root', 'K1': 'V1'} + with mock.patch.dict("os.environ", values=extra): + out, err = util.subp( + self.printenv + ['FOO', 'HOME', 'K1', 'K2'], capture=True, + update_env={'HOME': '/myhome', 'K2': 'V2'}) + + self.assertEqual( + ['FOO=BAR', 'HOME=/myhome', 'K1=V1', 'K2=V2'], out.splitlines()) + def test_returns_none_if_no_capture(self): (out, err) = util.subp(self.stdin2out, data=b'', capture=False) self.assertEqual(err, None) -- cgit v1.2.3 From 0439d8a17d181a2546f2f7cb2d71a04bbb13b186 Mon Sep 17 00:00:00 2001 From: Robert Schweikert Date: Thu, 15 Sep 2016 12:05:15 -0400 Subject: Decode unicode types in decode_binary The test in decode_binary for six.text_type was incorrect as that includes unicode type in Python 2 which should actually be decoded. When the type is string_types we now properly check only for basestring and str in Python 2 and Python 3 respectively and return the given blob without making an attempt to decode. --- cloudinit/util.py | 2 +- tests/unittests/test_util.py | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) (limited to 'tests/unittests/test_util.py') diff --git a/cloudinit/util.py b/cloudinit/util.py index 05cb587c..eb3e5899 100644 --- a/cloudinit/util.py +++ b/cloudinit/util.py @@ -154,7 +154,7 @@ def target_path(target, path=None): def decode_binary(blob, encoding='utf-8'): # Converts a binary type into a text type using given encoding. - if isinstance(blob, six.text_type): + if isinstance(blob, six.string_types): return blob return blob.decode(encoding) diff --git a/tests/unittests/test_util.py b/tests/unittests/test_util.py index 30f603cb..fc6b9d40 100644 --- a/tests/unittests/test_util.py +++ b/tests/unittests/test_util.py @@ -603,4 +603,12 @@ class TestSubp(helpers.TestCase): self.assertEqual("/target/my/path/", util.target_path("/target/", "///my/path/")) + +class TestEncode(helpers.TestCase): + """Test the encoding functions""" + def test_decode_binary_plain_text_with_hex(self): + blob = 'BOOTABLE_FLAG=\x80init=/bin/systemd' + text = util.decode_binary(blob) + self.assertEqual(text, blob) + # vi: ts=4 expandtab -- cgit v1.2.3 From e8730078df8c99696b1b684e09c803eef7c4926c Mon Sep 17 00:00:00 2001 From: Scott Moser Date: Fri, 30 Sep 2016 15:53:42 -0400 Subject: Fix python2.6 things found running in centos 6. This gets the tests running in centos 6. * ProcessExecutionError: remove setting of .message Nothing in cloud-init seems to use .message anywhere, so it does not seem necessary. The reason to change it is that on 2.6 it spits out: cloudinit/util.py:286: DeprecationWarning: BaseException.message * tox.ini: add a centos6 environment the tox versions listed here replicate a centos6 install with packages from EPEL. You will still need a python2.6 to run this env so we do not enable it by default. --- cloudinit/sources/DataSourceAltCloud.py | 6 ++---- cloudinit/sources/helpers/azure.py | 2 +- cloudinit/util.py | 7 ++----- tests/unittests/test_handler/test_handler_apt_conf_v1.py | 2 +- tests/unittests/test_util.py | 2 +- tox.ini | 16 ++++++++++++++++ 6 files changed, 23 insertions(+), 12 deletions(-) (limited to 'tests/unittests/test_util.py') diff --git a/cloudinit/sources/DataSourceAltCloud.py b/cloudinit/sources/DataSourceAltCloud.py index 48136f7c..20345389 100644 --- a/cloudinit/sources/DataSourceAltCloud.py +++ b/cloudinit/sources/DataSourceAltCloud.py @@ -195,8 +195,7 @@ class DataSourceAltCloud(sources.DataSource): (cmd_out, _err) = util.subp(cmd) LOG.debug(('Command: %s\nOutput%s') % (' '.join(cmd), cmd_out)) except ProcessExecutionError as _err: - util.logexc(LOG, 'Failed command: %s\n%s', ' '.join(cmd), - _err.message) + util.logexc(LOG, 'Failed command: %s\n%s', ' '.join(cmd), _err) return False except OSError as _err: util.logexc(LOG, 'Failed command: %s\n%s', ' '.join(cmd), _err) @@ -211,8 +210,7 @@ class DataSourceAltCloud(sources.DataSource): (cmd_out, _err) = util.subp(cmd) LOG.debug(('Command: %s\nOutput%s') % (' '.join(cmd), cmd_out)) except ProcessExecutionError as _err: - util.logexc(LOG, 'Failed command: %s\n%s', ' '.join(cmd), - _err.message) + util.logexc(LOG, 'Failed command: %s\n%s', ' '.join(cmd), _err) return False except OSError as _err: util.logexc(LOG, 'Failed command: %s\n%s', ' '.join(cmd), diff --git a/cloudinit/sources/helpers/azure.py b/cloudinit/sources/helpers/azure.py index 689ed4cc..1b3e9b70 100644 --- a/cloudinit/sources/helpers/azure.py +++ b/cloudinit/sources/helpers/azure.py @@ -232,7 +232,7 @@ class WALinuxAgentShim(object): def _get_value_from_leases_file(fallback_lease_file): leases = [] content = util.load_file(fallback_lease_file) - LOG.debug("content is {}".format(content)) + LOG.debug("content is %s", content) for line in content.splitlines(): if 'unknown-245' in line: # Example line from Ubuntu diff --git a/cloudinit/util.py b/cloudinit/util.py index eb3e5899..4cff83c5 100644 --- a/cloudinit/util.py +++ b/cloudinit/util.py @@ -199,7 +199,7 @@ def fully_decoded_payload(part): encoding = charset.input_codec else: encoding = 'utf-8' - return cte_payload.decode(encoding, errors='surrogateescape') + return cte_payload.decode(encoding, 'surrogateescape') return cte_payload @@ -282,9 +282,6 @@ class ProcessExecutionError(IOError): 'reason': self.reason, } IOError.__init__(self, message) - # For backward compatibility with Python 2. - if not hasattr(self, 'message'): - self.message = message class SeLinuxGuard(object): @@ -1821,7 +1818,7 @@ def subp(args, data=None, rcs=None, env=None, capture=True, shell=False, def ldecode(data, m='utf-8'): if not isinstance(data, bytes): return data - return data.decode(m, errors=decode) + return data.decode(m, decode) out = ldecode(out) err = ldecode(err) diff --git a/tests/unittests/test_handler/test_handler_apt_conf_v1.py b/tests/unittests/test_handler/test_handler_apt_conf_v1.py index 45714efd..64acc3e0 100644 --- a/tests/unittests/test_handler/test_handler_apt_conf_v1.py +++ b/tests/unittests/test_handler/test_handler_apt_conf_v1.py @@ -118,7 +118,7 @@ class TestConversion(TestCase): def test_convert_with_apt_mirror(self): mirror = 'http://my.mirror/ubuntu' f = cc_apt_configure.convert_to_v3_apt_format({'apt_mirror': mirror}) - self.assertIn(mirror, {m['uri'] for m in f['apt']['primary']}) + self.assertIn(mirror, set(m['uri'] for m in f['apt']['primary'])) def test_no_old_content(self): mirror = 'http://my.mirror/ubuntu' diff --git a/tests/unittests/test_util.py b/tests/unittests/test_util.py index fc6b9d40..881509aa 100644 --- a/tests/unittests/test_util.py +++ b/tests/unittests/test_util.py @@ -553,7 +553,7 @@ class TestSubp(helpers.TestCase): def test_subp_decode_invalid_utf8_replaces(self): (out, _err) = util.subp(self.stdin2out, capture=True, data=self.utf8_invalid) - expected = self.utf8_invalid.decode('utf-8', errors='replace') + expected = self.utf8_invalid.decode('utf-8', 'replace') self.assertEqual(out, expected) def test_subp_decode_strict_raises(self): diff --git a/tox.ini b/tox.ini index 729de2a6..277858ed 100644 --- a/tox.ini +++ b/tox.ini @@ -59,3 +59,19 @@ deps = pyflakes==1.1.0 flake8==2.5.4 hacking==0.10.2 + +[testenv:centos6] +basepython = python2.6 +commands = nosetests {posargs:tests} +deps = + # requirements + argparse==1.2.1 + jinja2==2.2.1 + pyyaml==3.10 + PrettyTable==0.7.2 + oauthlib==0.6.0 + configobj==4.6.0 + requests==2.6.0 + jsonpatch==1.2 + six==1.9.0 + -r{toxinidir}/test-requirements.txt -- cgit v1.2.3 From 3416e2ee7f65defdb15aab861a85767d13e8c34c Mon Sep 17 00:00:00 2001 From: Robert Schweikert Date: Sat, 29 Oct 2016 09:29:53 -0400 Subject: dmidecode: Allow dmidecode to be used on aarch64 aarch64 systems have functional dmidecode, so allow that to be used. - aarch64 has support for dmidecode as well --- cloudinit/util.py | 3 ++- tests/unittests/test_util.py | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'tests/unittests/test_util.py') diff --git a/cloudinit/util.py b/cloudinit/util.py index 4b3fd0cb..9a3d3cd7 100644 --- a/cloudinit/util.py +++ b/cloudinit/util.py @@ -2342,7 +2342,8 @@ def read_dmi_data(key): # running dmidecode can be problematic on some arches (LP: #1243287) uname_arch = os.uname()[4] if not (uname_arch == "x86_64" or - (uname_arch.startswith("i") and uname_arch[2:] == "86")): + (uname_arch.startswith("i") and uname_arch[2:] == "86") or + uname_arch == 'aarch64'): LOG.debug("dmidata is not supported on %s", uname_arch) return None diff --git a/tests/unittests/test_util.py b/tests/unittests/test_util.py index 881509aa..f6a8ab75 100644 --- a/tests/unittests/test_util.py +++ b/tests/unittests/test_util.py @@ -386,7 +386,7 @@ class TestReadDMIData(helpers.FilesystemMockingTestCase): dmi_name = 'use-dmidecode' self._configure_dmidecode_return(dmi_name, dmi_val) - expected = {'armel': None, 'aarch64': None, 'x86_64': dmi_val} + expected = {'armel': None, 'aarch64': dmi_val, 'x86_64': dmi_val} found = {} # we do not run the 'dmi-decode' binary on some arches # verify that anything requested that is not in the sysfs dir -- cgit v1.2.3