diff --git a/Dockerfile.build b/Dockerfile.build index 6a67dd7..7a98d5d 100644 --- a/Dockerfile.build +++ b/Dockerfile.build @@ -1,4 +1,5 @@ FROM python:2.7 +#FROM python:3.6 # Install Docker ENV DOCKER_CONFIG=/tmp/ diff --git a/Makefile b/Makefile index f1284a9..51d697d 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,7 @@ # Get docker api version and set the compose file version accordingly DOCKER_API_VERSION = $(shell python docker_test_tools/api_version.py) -COMPOSE_FILE_VERSION = $(shell python -c 'print "2.1" if $(DOCKER_API_VERSION) >= "1.24" else "2"') +COMPOSE_FILE_VERSION = $(shell python -c 'print("2.1" if "$(DOCKER_API_VERSION)" >= "1.24" else "2")') DTT_COMPOSE_PATH=tests/resources/docker-compose-v$(COMPOSE_FILE_VERSION).yml all: coverage nose2 pytest dist/docker-test-tools-*.tar.gz diff --git a/docker_test_tools/api_version.py b/docker_test_tools/api_version.py index 0a78b64..07e99a2 100755 --- a/docker_test_tools/api_version.py +++ b/docker_test_tools/api_version.py @@ -8,4 +8,4 @@ def get_server_api_version(): return server_versions['ApiVersion'] if __name__ == '__main__': - print get_server_api_version() + print(get_server_api_version()) diff --git a/docker_test_tools/config.py b/docker_test_tools/config.py index 4f719ba..a474076 100644 --- a/docker_test_tools/config.py +++ b/docker_test_tools/config.py @@ -1,5 +1,5 @@ import os -import ConfigParser +from six.moves import configparser class Config(object): @@ -87,7 +87,7 @@ def get_file_config(self, config_path): if not os.path.exists(config_path): raise RuntimeError("Invalid configuration path: %s" % config_path) - config_reader = ConfigParser.ConfigParser() + config_reader = configparser.ConfigParser() config_reader.read(config_path) read_options = config_reader.options(self.SECTION_NAME) diff --git a/docker_test_tools/environment.py b/docker_test_tools/environment.py index a288402..0f34e5c 100644 --- a/docker_test_tools/environment.py +++ b/docker_test_tools/environment.py @@ -56,7 +56,7 @@ def get_services(self): except subprocess.CalledProcessError as error: raise RuntimeError("Failed getting environment services, reason: %s" % error.output) - return services_output.strip().split('\n') + return self._to_str(services_output).strip().split('\n') def setup(self): """Sets up the environment using docker commands. @@ -148,7 +148,7 @@ def split_logs(self): services_log_files[service_name].write(message) finally: - for services_log_file in services_log_files.itervalues(): + for services_log_file in services_log_files.values(): services_log_file.close() def remove_containers(self): @@ -270,13 +270,15 @@ def get_container_id(self, name): """ self.validate_service_name(name) try: - return subprocess.check_output( + output = subprocess.check_output( ['docker-compose', '-f', self.compose_path, '-p', self.project_name, 'ps', '-q', name], stderr=subprocess.STDOUT, env=self.environment_variables ) except subprocess.CalledProcessError as error: raise RuntimeError("Failed getting container %s id, reason: %s" % (name, error.output)) + return self._to_str(output) + def is_container_ready(self, name): """"Return True if the container is in ready state. @@ -298,6 +300,7 @@ def is_container_ready(self, name): log.warning("Failed getting container %s state, reason: %s", name, error.output) return False + status_output = self._to_str(status_output) if '"Health":' in status_output: is_ready = '"Status":"healthy"' in status_output else: @@ -433,3 +436,18 @@ def _get_environment_variables(): env = os.environ.copy() env['COMPOSE_API_VERSION'] = env['DOCKER_API_VERSION'] = server_api_version return env + + @staticmethod + def _to_str(value): + """ + For each value, return the value as string + For python3 compatibility + """ + + if isinstance(value, str): + return value + + if isinstance(value, bytes): + return value.decode('utf-8') + + raise Exception("Type {} was not converted to string".format(type(value))) diff --git a/docker_test_tools/utils.py b/docker_test_tools/utils.py index 13b74c6..8f03e36 100644 --- a/docker_test_tools/utils.py +++ b/docker_test_tools/utils.py @@ -1,5 +1,5 @@ import logging -import httplib +from six.moves import http_client import waiting import requests @@ -27,7 +27,7 @@ def run_health_checks(checks, interval=1, timeout=60): return False -def is_responsive(address, expected_status=httplib.OK): +def is_responsive(address, expected_status=http_client.OK): """Return True if the address is responsive. :param string address: url address 'hostname:port'. @@ -40,7 +40,7 @@ def is_responsive(address, expected_status=httplib.OK): return False -def get_health_check(service_name, url, expected_status=httplib.OK): +def get_health_check(service_name, url, expected_status=http_client.OK): """Return a function used to determine if the given service is responsive. :param string service_name: service name. diff --git a/docker_test_tools/wiremock.py b/docker_test_tools/wiremock.py index 7e610a6..2bdbb79 100644 --- a/docker_test_tools/wiremock.py +++ b/docker_test_tools/wiremock.py @@ -5,7 +5,7 @@ import os import json import glob -import httplib +from six.moves import http_client import logging import requests @@ -100,7 +100,7 @@ def get_request_journal(self): :raise ValueError: on failure to retrieve journal from Wiremock admin API. """ response = requests.get(self.requests_url) - if response.status_code != httplib.OK: + if response.status_code != http_client.OK: raise ValueError(response.text, response.status_code) response_body = json.loads(response.text) return response_body["requests"] diff --git a/tests/integration/test_example.py b/tests/integration/test_example.py index d6c843b..bf428c1 100644 --- a/tests/integration/test_example.py +++ b/tests/integration/test_example.py @@ -1,5 +1,5 @@ import os -import httplib +from six.moves import http_client import logging import requests @@ -34,15 +34,15 @@ def setUp(self): def test_services_sanity(self): """Validate services are responsive once the test start.""" log.info('Validating consul container is responsive') - self.assertEquals(requests.get('http://consul.service:8500').status_code, httplib.OK) + self.assertEquals(requests.get('http://consul.service:8500').status_code, http_client.OK) log.info('Validating wiremock container is responsive') - self.assertEquals(requests.get('http://mocked.service:9999/__admin').status_code, httplib.OK) + self.assertEquals(requests.get('http://mocked.service:9999/__admin').status_code, http_client.OK) def test_service_down(self): """Validate service down scenario.""" log.info('Validating consul container is responsive') - self.assertEquals(requests.get('http://consul.service:8500').status_code, httplib.OK) + self.assertEquals(requests.get('http://consul.service:8500').status_code, http_client.OK) log.info('Validating consul container is unresponsive while in `container_down` context') with self.controller.container_down(name='consul.service', health_check=consul_health_check): @@ -50,12 +50,12 @@ def test_service_down(self): requests.get('http://consul.service:8500') log.info('Validating consul container has recovered and is responsive') - self.assertEquals(requests.get('http://consul.service:8500').status_code, httplib.OK) + self.assertEquals(requests.get('http://consul.service:8500').status_code, http_client.OK) def test_service_stopped(self): """Validate service stopped scenario.""" log.info('Validating consul container is responsive') - self.assertEquals(requests.get('http://consul.service:8500').status_code, httplib.OK) + self.assertEquals(requests.get('http://consul.service:8500').status_code, http_client.OK) log.info('Validating consul container is unresponsive while in `container_stopped` context') with self.controller.container_stopped(name='consul.service', health_check=consul_health_check): @@ -63,12 +63,12 @@ def test_service_stopped(self): requests.get('http://consul.service:8500') log.info('Validating consul container has recovered and is responsive') - self.assertEquals(requests.get('http://consul.service:8500').status_code, httplib.OK) + self.assertEquals(requests.get('http://consul.service:8500').status_code, http_client.OK) def test_service_paused(self): """Validate service paused scenario.""" log.info('Validating consul container is responsive') - self.assertEquals(requests.get('http://consul.service:8500', timeout=2).status_code, httplib.OK) + self.assertEquals(requests.get('http://consul.service:8500', timeout=2).status_code, http_client.OK) log.info('Validating consul container is unresponsive while in `container_paused` context') with self.controller.container_paused(name='consul.service', health_check=consul_health_check): @@ -76,19 +76,19 @@ def test_service_paused(self): requests.get('http://consul.service:8500', timeout=2) log.info('Validating consul container has recovered and is responsive') - self.assertEquals(requests.get('http://consul.service:8500', timeout=2).status_code, httplib.OK) + self.assertEquals(requests.get('http://consul.service:8500', timeout=2).status_code, http_client.OK) def test_mocked_service_configuration(self): """Validate wiremock service.""" log.info('Validating mocked service fail to find `test` endpoint') - self.assertEquals(requests.post('http://mocked.service:9999/test').status_code, httplib.NOT_FOUND) + self.assertEquals(requests.post('http://mocked.service:9999/test').status_code, http_client.NOT_FOUND) log.info('Use WiremockController to stub the service `test` endpoint') stubs_dir_path = os.path.join(os.path.dirname(__file__), '..', 'resources', 'wiremock_stubs') self.wiremock.set_mapping_from_dir(stubs_dir_path) log.info('Validating mocked service response on `test` endpoint') - self.assertEquals(requests.post('http://mocked.service:9999/test').status_code, httplib.OK) + self.assertEquals(requests.post('http://mocked.service:9999/test').status_code, http_client.OK) def test_mocked_service_request_journal(self): """Validate wiremock request journal.""" diff --git a/tests/ut/nose2.cfg b/tests/ut/nose2.cfg index 74d8886..a1b6834 100755 --- a/tests/ut/nose2.cfg +++ b/tests/ut/nose2.cfg @@ -4,10 +4,6 @@ plugins = nose2.plugins.mp nose2.plugins.layers nose2.plugins.junitxml -[multiprocess] -always-on = True -processes = 4 - [coverage] always-on = True coverage = docker_test_tools diff --git a/tests/ut/test_config.py b/tests/ut/test_config.py index e80f411..2cc7c2d 100644 --- a/tests/ut/test_config.py +++ b/tests/ut/test_config.py @@ -4,7 +4,7 @@ import tempfile import unittest -import ConfigParser +from six.moves import configparser from docker_test_tools.config import Config @@ -84,19 +84,19 @@ def test_bad_config_path(self): def test_bad_section_name(self): """Try parsing an invalid config file path and validate operation failure.""" test_config_path = self.create_config_file(config_input={}, section='bad') - with self.assertRaises(ConfigParser.NoSectionError): + with self.assertRaises(configparser.NoSectionError): Config(config_path=test_config_path) def create_config_file(self, config_input, section='environment'): """Create a config file based on the given dictionary.""" test_config_path = os.path.join(self.test_dir, 'test.txt') - parser = ConfigParser.ConfigParser() + parser = configparser.ConfigParser() with open(test_config_path, 'w') as cfgfile: parser.add_section(section) - for option, value in config_input.iteritems(): - parser.set(section, option, value) + for option, value in config_input.items(): + parser.set(section, option, str(value)) parser.write(cfgfile) return test_config_path diff --git a/tests/ut/test_environment.py b/tests/ut/test_environment.py index 9f9683d..a5e0623 100644 --- a/tests/ut/test_environment.py +++ b/tests/ut/test_environment.py @@ -2,6 +2,7 @@ import mock import unittest import subprocess +from six.moves import builtins from waiting import TimeoutExpired from docker_test_tools import environment @@ -74,6 +75,7 @@ def test_container_methods_happy_flow(self, mocked_check_output): stderr=subprocess.STDOUT, env=self.ENVIRONMENT_VARIABLES ) + mocked_check_output.return_value = "DOCKER_SERVICE" self.controller.get_container_id(service_name) mocked_check_output.assert_called_with( ['docker-compose', '-f', self.compose_path, '-p', self.project_name, 'ps', '-q', service_name], @@ -353,7 +355,7 @@ def test_stop_log_collection(self, split_logs_mock): def test_start_log_collection(self, mocked_popen): """"Validate the environment start_log_collection method.""" controller = self.get_controller() - with mock.patch("__builtin__.open", mock.mock_open()): + with mock.patch("{}.open".format(builtins.__name__), mock.mock_open()): controller.start_log_collection() mocked_popen.assert_called_with( diff --git a/tests/ut/test_wiremock.py b/tests/ut/test_wiremock.py index 9226010..7c6c780 100644 --- a/tests/ut/test_wiremock.py +++ b/tests/ut/test_wiremock.py @@ -1,5 +1,5 @@ import mock -import httplib +from six.moves import http_client import unittest from docker_test_tools import wiremock @@ -104,7 +104,7 @@ def test_get_request_journal(self): """Test 'get_request_journal' method.""" mock_response = mock.Mock() - mock_response.status_code = httplib.OK + mock_response.status_code = http_client.OK mock_response.text = self.journal_json mock_get = mock.Mock(return_value=mock_response) @@ -118,7 +118,7 @@ def test_error_getting_request_journal(self): """Test HTTP error while getting request journal.""" mock_response = mock.Mock() - mock_response.status_code = httplib.NOT_FOUND + mock_response.status_code = http_client.NOT_FOUND mock_get = mock.Mock(return_value=mock_response) with mock.patch("requests.get", mock_get): @@ -128,7 +128,7 @@ def test_get_matching_requests(self): """Test 'get_matching_requests' method.""" mock_response = mock.Mock() - mock_response.status_code = httplib.OK + mock_response.status_code = http_client.OK mock_response.text = self.journal_json mock_get = mock.Mock(return_value=mock_response)