From 08d00b0c41e965129849eb58f73ddd865e62e3b5 Mon Sep 17 00:00:00 2001 From: Steve Baker Date: Fri, 21 Nov 2014 11:06:50 +1300 Subject: [PATCH] Start of docker hook unit tests Other hooks process json then execute commands. The docker hook makes socket API calls via the docker-py module. For this reason a different approach has been taken with testing this hook: - symlink hook-docker.py to the tests package as hook_docker.py - in the test, mock out the docker import and run main() directly Change-Id: Ia069b2cc0db71952732dea310a8986b73981b656 --- .../install.d/hook-docker.py | 24 ++++--- tests/software_config/hook_docker.py | 1 + tests/software_config/test_hook_docker.py | 63 +++++++++++++++++++ 3 files changed, 78 insertions(+), 10 deletions(-) create mode 120000 tests/software_config/hook_docker.py create mode 100644 tests/software_config/test_hook_docker.py diff --git a/hot/software-config/elements/heat-config-docker/install.d/hook-docker.py b/hot/software-config/elements/heat-config-docker/install.d/hook-docker.py index b9b8bcee..173be11a 100755 --- a/hot/software-config/elements/heat-config-docker/install.d/hook-docker.py +++ b/hot/software-config/elements/heat-config-docker/install.d/hook-docker.py @@ -18,7 +18,11 @@ import logging import os import sys -import docker +try: + import docker +except ImportError: + docker = None + import yaml @@ -142,7 +146,7 @@ def update_pod_state(pod_state, is_container_running): def configure_logging(): log = logging.getLogger('heat-config') - log.setLevel('DEBUG') + log.setLevel(logging.DEBUG) formatter = logging.Formatter( '[%(asctime)s] (%(name)s) [%(levelname)s] %(message)s') @@ -154,23 +158,23 @@ def configure_logging(): deploy_stdout = cStringIO.StringIO() handler = logging.StreamHandler(deploy_stdout) handler.setFormatter(formatter) - handler.setLevel('DEBUG') + handler.setLevel(logging.DEBUG) log.addHandler(handler) deploy_stderr = cStringIO.StringIO() handler = logging.StreamHandler(deploy_stderr) handler.setFormatter(formatter) - handler.setLevel('DEBUG') + handler.setLevel(logging.WARN) log.addHandler(handler) return log, deploy_stdout, deploy_stderr -def main(argv=sys.argv): +def main(argv=sys.argv, sys_stdin=sys.stdin, sys_stdout=sys.stdout): (log, deploy_stdout, deploy_stderr) = configure_logging() client = get_client(log) - c = json.load(sys.stdin) + c = json.load(sys_stdin) pod_name = c.get('name') input_values = dict((i['name'], i['value']) for i in c['inputs']) @@ -182,8 +186,8 @@ def main(argv=sys.argv): else: yaml_config = yaml.load(config) - containers = yaml_config.get('containers') - volumes = yaml_config.get('volumes') + containers = yaml_config.get('containers', []) + volumes = yaml_config.get('volumes', []) remove_all_containers_for_pod(client, log, pod_name) @@ -196,7 +200,7 @@ def main(argv=sys.argv): 'deploy_stderr': deploy_stderr.getvalue(), 'deploy_status_code': 0, } - json.dump(response, sys.stdout) + json.dump(response, sys_stdout) return mount_external_volumes(log, volumes) @@ -260,7 +264,7 @@ def main(argv=sys.argv): 'deploy_stderr': deploy_stderr.getvalue(), 'deploy_status_code': pod_state, } - json.dump(response, sys.stdout) + json.dump(response, sys_stdout) if __name__ == '__main__': diff --git a/tests/software_config/hook_docker.py b/tests/software_config/hook_docker.py new file mode 120000 index 00000000..64d45289 --- /dev/null +++ b/tests/software_config/hook_docker.py @@ -0,0 +1 @@ +../../hot/software-config/elements/heat-config-docker/install.d/hook-docker.py \ No newline at end of file diff --git a/tests/software_config/test_hook_docker.py b/tests/software_config/test_hook_docker.py new file mode 100644 index 00000000..c8a426a2 --- /dev/null +++ b/tests/software_config/test_hook_docker.py @@ -0,0 +1,63 @@ +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + + +import cStringIO +import json +import mock +import testtools +from testtools import matchers + +from tests.software_config import hook_docker + + +class HookDockerTest(testtools.TestCase): + + def setUp(self): + super(HookDockerTest, self).setUp() + docker = mock.MagicMock() + self.docker_client = mock.MagicMock() + docker.Client.return_value = self.docker_client + self.docker_client.version.return_value = { + 'ApiVersion': '1.3.0' + } + hook_docker.docker = docker + + def assertLogEntries(self, entries, log): + for (entry, line) in zip(entries, log.split('\n')): + self.assertThat(line, matchers.EndsWith(entry)) + + def test_empty_input(self): + config = { + 'name': 'deployment_name', + 'options': {}, + 'inputs': [], + 'outputs': [], + 'config': {} + } + sys_stdin = cStringIO.StringIO(json.dumps(config)) + sys_stdout = cStringIO.StringIO() + hook_docker.main([], sys_stdin, sys_stdout) + + response = json.loads(sys_stdout.getvalue()) + + self.assertLogEntries([ + 'Connecting to unix:///var/run/docker.sock', + 'Connected to version 1.3.0', + 'Removing all containers from deployment_name' + ], response.pop('deploy_stdout')) + + self.assertLogEntries([], response.pop('deploy_stderr')) + + self.assertEqual( + {"deploy_status_code": 0}, response)