111 lines
3.4 KiB
Python
111 lines
3.4 KiB
Python
|
from __future__ import absolute_import
|
||
|
import os
|
||
|
import time
|
||
|
|
||
|
|
||
|
INTEGRATION_TESTS = os.environ.get('INTEGRATION_TESTS', False)
|
||
|
|
||
|
|
||
|
if INTEGRATION_TESTS:
|
||
|
from compose.cli.command import get_project
|
||
|
from compose.service import BuildAction
|
||
|
from compose.service import ConvergenceStrategy
|
||
|
|
||
|
|
||
|
class ComposeMixin(object):
|
||
|
"""
|
||
|
Manage docker-compose to ensure that needed services are running during tests
|
||
|
"""
|
||
|
|
||
|
# List of required services to run INTEGRATION_TESTS
|
||
|
COMPOSE_SERVICES = []
|
||
|
|
||
|
# docker-compose.yml dir path
|
||
|
COMPOSE_PROJECT_DIR = '.'
|
||
|
|
||
|
# timeout waiting for health (seconds)
|
||
|
COMPOSE_TIMEOUT = 300
|
||
|
|
||
|
@classmethod
|
||
|
def compose_up(cls):
|
||
|
"""
|
||
|
Ensure *only* the services defined under `COMPOSE_SERVICES` are running and healthy
|
||
|
"""
|
||
|
if not INTEGRATION_TESTS or not cls.COMPOSE_SERVICES:
|
||
|
return
|
||
|
|
||
|
if os.environ.get('NO_COMPOSE'):
|
||
|
return
|
||
|
|
||
|
def print_logs(container):
|
||
|
print("---- " + container.name_without_project)
|
||
|
print(container.logs())
|
||
|
print("----")
|
||
|
|
||
|
def is_healthy(container):
|
||
|
return container.inspect()['State']['Health']['Status'] == 'healthy'
|
||
|
|
||
|
project = cls.compose_project()
|
||
|
project.up(
|
||
|
strategy=ConvergenceStrategy.always,
|
||
|
service_names=cls.COMPOSE_SERVICES,
|
||
|
do_build=BuildAction.force,
|
||
|
timeout=30)
|
||
|
|
||
|
# Wait for them to be healthy
|
||
|
start = time.time()
|
||
|
while True:
|
||
|
containers = project.containers(
|
||
|
service_names=cls.COMPOSE_SERVICES,
|
||
|
stopped=True)
|
||
|
|
||
|
healthy = True
|
||
|
for container in containers:
|
||
|
if not container.is_running:
|
||
|
print_logs(container)
|
||
|
raise Exception(
|
||
|
"Container %s unexpectedly finished on startup" %
|
||
|
container.name_without_project)
|
||
|
if not is_healthy(container):
|
||
|
healthy = False
|
||
|
break
|
||
|
|
||
|
if healthy:
|
||
|
break
|
||
|
|
||
|
time.sleep(1)
|
||
|
timeout = time.time() - start > cls.COMPOSE_TIMEOUT
|
||
|
if timeout:
|
||
|
for container in containers:
|
||
|
if not is_healthy(container):
|
||
|
print_logs(container)
|
||
|
raise Exception(
|
||
|
"Timeout while waiting for healthy "
|
||
|
"docker-compose services: %s" %
|
||
|
','.join(cls.COMPOSE_SERVICES))
|
||
|
|
||
|
@classmethod
|
||
|
def compose_down(cls):
|
||
|
"""
|
||
|
Stop all running containers
|
||
|
"""
|
||
|
if INTEGRATION_TESTS and cls.COMPOSE_SERVICES:
|
||
|
cls.compose_project().kill(service_names=cls.COMPOSE_SERVICES)
|
||
|
|
||
|
@classmethod
|
||
|
def compose_hosts(cls):
|
||
|
if not INTEGRATION_TESTS or not cls.COMPOSE_SERVICES:
|
||
|
return []
|
||
|
|
||
|
hosts = []
|
||
|
for container in cls.compose_project().containers(service_names=cls.COMPOSE_SERVICES):
|
||
|
network_settings = container.inspect()['NetworkSettings']
|
||
|
for network in network_settings['Networks'].values():
|
||
|
if network['IPAddress']:
|
||
|
hosts.append(network['IPAddress'])
|
||
|
return hosts
|
||
|
|
||
|
@classmethod
|
||
|
def compose_project(cls):
|
||
|
return get_project(cls.COMPOSE_PROJECT_DIR, project_name=os.environ.get('DOCKER_COMPOSE_PROJECT_NAME'))
|