From b2c234b2056b9d8cb9f6eda268c2cf1845f88371 Mon Sep 17 00:00:00 2001 From: Adam Israel Date: Fri, 5 Apr 2019 10:17:25 -0400 Subject: [PATCH] Bug 666: Fix window_size overflow with Paramiko This commit fixes integration testing around bug fixes in the sshproxy layer that were causing a window_size overflow. This also improves reliability around testing machine charms, by verifying the sshd service is running inside the target machine (lxd) before running tests. Change-Id: I465d51521bf87b8e4b3dc5cac07c163fac836393 Signed-off-by: Adam Israel --- tests/base.py | 65 +++++++++++++++++-- tests/charms/layers/broken/tests/00-setup | 5 -- tests/charms/layers/broken/tests/10-deploy | 35 ---------- tests/charms/layers/metrics-ci/tests/00-setup | 5 -- .../charms/layers/metrics-ci/tests/10-deploy | 35 ---------- .../layers/metrics-proxy-ci/tests/00-setup | 5 -- .../layers/metrics-proxy-ci/tests/10-deploy | 35 ---------- tests/charms/layers/simple/tests/00-setup | 5 -- tests/charms/layers/simple/tests/10-deploy | 35 ---------- tests/integration/test_charm_native.py | 1 - tests/integration/test_metrics_proxy.py | 9 ++- .../integration/test_non_string_parameter.py | 8 +-- tox.ini | 6 +- 13 files changed, 76 insertions(+), 173 deletions(-) delete mode 100644 tests/charms/layers/broken/tests/00-setup delete mode 100644 tests/charms/layers/broken/tests/10-deploy delete mode 100755 tests/charms/layers/metrics-ci/tests/00-setup delete mode 100755 tests/charms/layers/metrics-ci/tests/10-deploy delete mode 100644 tests/charms/layers/metrics-proxy-ci/tests/00-setup delete mode 100644 tests/charms/layers/metrics-proxy-ci/tests/10-deploy delete mode 100755 tests/charms/layers/simple/tests/00-setup delete mode 100755 tests/charms/layers/simple/tests/10-deploy diff --git a/tests/base.py b/tests/base.py index 3ae5f4f..a0a2b78 100644 --- a/tests/base.py +++ b/tests/base.py @@ -230,6 +230,25 @@ def create_lxd_container(public_key=None, name="test_name"): ) ) + try: + waitcount = 0 + while waitcount <= 5: + if is_sshd_running(container): + break + waitcount += 1 + time.sleep(1) + if waitcount >= 5: + debug("couldn't detect sshd running") + raise Exception("Unable to verify container sshd") + + except Exception as ex: + debug( + "Error checking sshd status on {}: {}".format( + test_machine, + ex, + ) + ) + # HACK: We need to give sshd a chance to bind to the interface, # and pylxd's container.execute seems to be broken and fails and/or # hangs trying to properly check if the service is up. @@ -246,6 +265,28 @@ def create_lxd_container(public_key=None, name="test_name"): return container +def is_sshd_running(container): + """Check if sshd is running in the container. + + Check to see if the sshd process is running and listening on port 22. + + :param container: The container to check + :return boolean: True if sshd is running. + """ + debug("Container: {}".format(container)) + try: + (rc, stdout, stderr) = container.execute( + ["service", "ssh", "status"] + ) + # If the status is a) found and b) running, the exit code will be 0 + if rc == 0: + return True + except Exception as ex: + debug("Failed to check sshd service status: {}".format(ex)) + + return False + + def destroy_lxd_container(container): """Stop and delete a LXD container. @@ -893,11 +934,20 @@ class TestN2VC(object): self._running = False self._stopping = True + # Destroy the network service + try: + await self.n2vc.DestroyNetworkService(self.ns_name) + except Exception as e: + debug( + "Error Destroying Network Service \"{}\": {}".format( + self.ns_name, + e, + ) + ) + + # Wait for the applications to be removed and delete the containers for application in self.charms: try: - await self.n2vc.RemoveCharms(self.ns_name, application) - - await self.n2vc.DestroyNetworkService(self.ns_name) while True: # Wait for the application to be removed @@ -907,7 +957,6 @@ class TestN2VC(object): application, ): break - await self.n2vc.DestroyNetworkService(self.ns_name) # Need to wait for the charm to finish, because native charms if self.state[application]['container']: @@ -1119,6 +1168,14 @@ class TestN2VC(object): debug("{} is done".format(application)) return + if status in ['error']: + # To test broken charms, if a charm enters an error state we should + # end the test + debug("{} is in an error state, stop the test.".format(application)) + # asyncio.ensure_future(self.stop()) + self.state[application]['done'] = True + assert False + if status in ["blocked"] and self.isproxy(application): if self.state[application]['phase'] == "deploy": debug("Configuring proxy charm for {}".format(application)) diff --git a/tests/charms/layers/broken/tests/00-setup b/tests/charms/layers/broken/tests/00-setup deleted file mode 100644 index f0616a5..0000000 --- a/tests/charms/layers/broken/tests/00-setup +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/bash - -sudo add-apt-repository ppa:juju/stable -y -sudo apt-get update -sudo apt-get install amulet python-requests -y diff --git a/tests/charms/layers/broken/tests/10-deploy b/tests/charms/layers/broken/tests/10-deploy deleted file mode 100644 index 9a26117..0000000 --- a/tests/charms/layers/broken/tests/10-deploy +++ /dev/null @@ -1,35 +0,0 @@ -#!/usr/bin/python3 - -import amulet -import requests -import unittest - - -class TestCharm(unittest.TestCase): - def setUp(self): - self.d = amulet.Deployment() - - self.d.add('simple') - self.d.expose('simple') - - self.d.setup(timeout=900) - self.d.sentry.wait() - - self.unit = self.d.sentry['simple'][0] - - def test_service(self): - # test we can access over http - page = requests.get('http://{}'.format(self.unit.info['public-address'])) - self.assertEqual(page.status_code, 200) - # Now you can use self.d.sentry[SERVICE][UNIT] to address each of the units and perform - # more in-depth steps. Each self.d.sentry[SERVICE][UNIT] has the following methods: - # - .info - An array of the information of that unit from Juju - # - .file(PATH) - Get the details of a file on that unit - # - .file_contents(PATH) - Get plain text output of PATH file from that unit - # - .directory(PATH) - Get details of directory - # - .directory_contents(PATH) - List files and folders in PATH on that unit - # - .relation(relation, service:rel) - Get relation data from return service - - -if __name__ == '__main__': - unittest.main() diff --git a/tests/charms/layers/metrics-ci/tests/00-setup b/tests/charms/layers/metrics-ci/tests/00-setup deleted file mode 100755 index f0616a5..0000000 --- a/tests/charms/layers/metrics-ci/tests/00-setup +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/bash - -sudo add-apt-repository ppa:juju/stable -y -sudo apt-get update -sudo apt-get install amulet python-requests -y diff --git a/tests/charms/layers/metrics-ci/tests/10-deploy b/tests/charms/layers/metrics-ci/tests/10-deploy deleted file mode 100755 index 7595ecf..0000000 --- a/tests/charms/layers/metrics-ci/tests/10-deploy +++ /dev/null @@ -1,35 +0,0 @@ -#!/usr/bin/python3 - -import amulet -import requests -import unittest - - -class TestCharm(unittest.TestCase): - def setUp(self): - self.d = amulet.Deployment() - - self.d.add('metrics-demo') - self.d.expose('metrics-demo') - - self.d.setup(timeout=900) - self.d.sentry.wait() - - self.unit = self.d.sentry['metrics-demo'][0] - - def test_service(self): - # test we can access over http - page = requests.get('http://{}'.format(self.unit.info['public-address'])) - self.assertEqual(page.status_code, 200) - # Now you can use self.d.sentry[SERVICE][UNIT] to address each of the units and perform - # more in-depth steps. Each self.d.sentry[SERVICE][UNIT] has the following methods: - # - .info - An array of the information of that unit from Juju - # - .file(PATH) - Get the details of a file on that unit - # - .file_contents(PATH) - Get plain text output of PATH file from that unit - # - .directory(PATH) - Get details of directory - # - .directory_contents(PATH) - List files and folders in PATH on that unit - # - .relation(relation, service:rel) - Get relation data from return service - - -if __name__ == '__main__': - unittest.main() diff --git a/tests/charms/layers/metrics-proxy-ci/tests/00-setup b/tests/charms/layers/metrics-proxy-ci/tests/00-setup deleted file mode 100644 index f0616a5..0000000 --- a/tests/charms/layers/metrics-proxy-ci/tests/00-setup +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/bash - -sudo add-apt-repository ppa:juju/stable -y -sudo apt-get update -sudo apt-get install amulet python-requests -y diff --git a/tests/charms/layers/metrics-proxy-ci/tests/10-deploy b/tests/charms/layers/metrics-proxy-ci/tests/10-deploy deleted file mode 100644 index 7595ecf..0000000 --- a/tests/charms/layers/metrics-proxy-ci/tests/10-deploy +++ /dev/null @@ -1,35 +0,0 @@ -#!/usr/bin/python3 - -import amulet -import requests -import unittest - - -class TestCharm(unittest.TestCase): - def setUp(self): - self.d = amulet.Deployment() - - self.d.add('metrics-demo') - self.d.expose('metrics-demo') - - self.d.setup(timeout=900) - self.d.sentry.wait() - - self.unit = self.d.sentry['metrics-demo'][0] - - def test_service(self): - # test we can access over http - page = requests.get('http://{}'.format(self.unit.info['public-address'])) - self.assertEqual(page.status_code, 200) - # Now you can use self.d.sentry[SERVICE][UNIT] to address each of the units and perform - # more in-depth steps. Each self.d.sentry[SERVICE][UNIT] has the following methods: - # - .info - An array of the information of that unit from Juju - # - .file(PATH) - Get the details of a file on that unit - # - .file_contents(PATH) - Get plain text output of PATH file from that unit - # - .directory(PATH) - Get details of directory - # - .directory_contents(PATH) - List files and folders in PATH on that unit - # - .relation(relation, service:rel) - Get relation data from return service - - -if __name__ == '__main__': - unittest.main() diff --git a/tests/charms/layers/simple/tests/00-setup b/tests/charms/layers/simple/tests/00-setup deleted file mode 100755 index f0616a5..0000000 --- a/tests/charms/layers/simple/tests/00-setup +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/bash - -sudo add-apt-repository ppa:juju/stable -y -sudo apt-get update -sudo apt-get install amulet python-requests -y diff --git a/tests/charms/layers/simple/tests/10-deploy b/tests/charms/layers/simple/tests/10-deploy deleted file mode 100755 index 9a26117..0000000 --- a/tests/charms/layers/simple/tests/10-deploy +++ /dev/null @@ -1,35 +0,0 @@ -#!/usr/bin/python3 - -import amulet -import requests -import unittest - - -class TestCharm(unittest.TestCase): - def setUp(self): - self.d = amulet.Deployment() - - self.d.add('simple') - self.d.expose('simple') - - self.d.setup(timeout=900) - self.d.sentry.wait() - - self.unit = self.d.sentry['simple'][0] - - def test_service(self): - # test we can access over http - page = requests.get('http://{}'.format(self.unit.info['public-address'])) - self.assertEqual(page.status_code, 200) - # Now you can use self.d.sentry[SERVICE][UNIT] to address each of the units and perform - # more in-depth steps. Each self.d.sentry[SERVICE][UNIT] has the following methods: - # - .info - An array of the information of that unit from Juju - # - .file(PATH) - Get the details of a file on that unit - # - .file_contents(PATH) - Get plain text output of PATH file from that unit - # - .directory(PATH) - Get details of directory - # - .directory_contents(PATH) - List files and folders in PATH on that unit - # - .relation(relation, service:rel) - Get relation data from return service - - -if __name__ == '__main__': - unittest.main() diff --git a/tests/integration/test_charm_native.py b/tests/integration/test_charm_native.py index 85a282e..7b2bda9 100644 --- a/tests/integration/test_charm_native.py +++ b/tests/integration/test_charm_native.py @@ -137,5 +137,4 @@ class TestCharm(base.TestN2VC): await asyncio.sleep(15) print("test_charm_native stopped") - return 'ok' diff --git a/tests/integration/test_metrics_proxy.py b/tests/integration/test_metrics_proxy.py index e7fa920..81501b0 100644 --- a/tests/integration/test_metrics_proxy.py +++ b/tests/integration/test_metrics_proxy.py @@ -109,7 +109,14 @@ class TestCharm(base.TestN2VC): juju: charm: metrics-proxy-ci proxy: true - """ + initial-config-primitive: + - seq: '1' + name: run + parameter: + - name: command + data-type: STRING + value: hostname +""" # @pytest.mark.serial @pytest.mark.asyncio diff --git a/tests/integration/test_non_string_parameter.py b/tests/integration/test_non_string_parameter.py index b93dfed..e15b790 100644 --- a/tests/integration/test_non_string_parameter.py +++ b/tests/integration/test_non_string_parameter.py @@ -13,9 +13,9 @@ class TestCharm(base.TestN2VC): NSD_YAML = """ nsd:nsd-catalog: nsd: - - id: charmnative-ns - name: charmnative-ns - short-name: charmnative-ns + - id: nonstring-ns + name: nonstring-ns + short-name: nonstring-ns description: NS with 1 VNFs charmnative-vnf connected by datanet and mgmtnet VLs version: '1.0' logo: osm.png @@ -143,5 +143,5 @@ class TestCharm(base.TestN2VC): print("Waiting for test to finish...") await asyncio.sleep(15) logging.debug("test_charm_non_string_parameter stopped") - + # assert False return 'ok' diff --git a/tox.ini b/tox.ini index b353ce8..c54d27d 100644 --- a/tox.ini +++ b/tox.ini @@ -15,7 +15,7 @@ markers = basepython=python3 usedevelop=True # for testing with other python versions -commands = py.test --ignore modules/ --tb native -ra -v -s -n auto -k 'not integration' -m 'not serial' {posargs} +commands = py.test --ignore modules/ --ignore tests/charms/ --tb native -ra -v -s -n auto -k 'not integration' -m 'not serial' {posargs} passenv = HOME VCA_HOST @@ -38,7 +38,7 @@ deps = [testenv:py3] # default tox env, excludes integration and serial tests commands = - pytest --ignore modules/ --tb native -ra -v -s -n auto -k 'not integration' -m 'not serial' {posargs} + pytest --ignore modules/ --ignore tests/charms/ --tb native -ra -v -s -n auto -k 'not integration' -m 'not serial' {posargs} [testenv:lint] envdir = {toxworkdir}/py3 @@ -49,7 +49,7 @@ deps = [testenv:integration] envdir = {toxworkdir}/py3 -commands = py.test --ignore modules/ --tb native -ra -v -s -n 1 -k 'integration' -m 'serial' {posargs} +commands = py.test --ignore modules/ --ignore tests/charms/ --tb native -ra -v -s -n 1 -k 'integration' -m 'serial' {posargs} [testenv:build] deps = -- 2.25.1