Make volumes_from and net containers first class dependencies and

assure that starting order is correct.  Added supporting unit and
integration tests as well.

Signed-off-by: Gil Clark <gilclark1@gmail.com>
This commit is contained in:
Gil Clark 2015-03-06 13:30:56 -08:00
commit 95f4e2c7c3
6 changed files with 429 additions and 41 deletions

View file

@ -44,6 +44,63 @@ class ProjectTest(DockerClientTestCase):
db = project.get_service('db')
self.assertEqual(db.volumes_from, [data_container])
project.kill()
project.remove_stopped()
def test_net_from_service(self):
project = Project.from_config(
name='composetest',
config={
'net': {
'image': 'busybox:latest',
'command': ["/bin/sleep", "300"]
},
'web': {
'image': 'busybox:latest',
'net': 'container:net',
'command': ["/bin/sleep", "300"]
},
},
client=self.client,
)
project.up()
web = project.get_service('web')
net = project.get_service('net')
self.assertEqual(web._get_net(), 'container:'+net.containers()[0].id)
project.kill()
project.remove_stopped()
def test_net_from_container(self):
net_container = Container.create(
self.client,
image='busybox:latest',
name='composetest_net_container',
command='/bin/sleep 300'
)
net_container.start()
project = Project.from_config(
name='composetest',
config={
'web': {
'image': 'busybox:latest',
'net': 'container:composetest_net_container'
},
},
client=self.client,
)
project.up()
web = project.get_service('web')
self.assertEqual(web._get_net(), 'container:'+net_container.id)
project.kill()
project.remove_stopped()
def test_start_stop_kill_remove(self):
web = self.create_service('web')
db = self.create_service('db')
@ -199,20 +256,86 @@ class ProjectTest(DockerClientTestCase):
project.kill()
project.remove_stopped()
def test_project_up_with_no_deps(self):
console = self.create_service('console')
db = self.create_service('db', volumes=['/var/db'])
web = self.create_service('web', links=[(db, 'db')])
project = Project('composetest', [web, db, console], self.client)
def test_project_up_starts_depends(self):
project = Project.from_config(
name='composetest',
config={
'console': {
'image': 'busybox:latest',
'command': ["/bin/sleep", "300"],
},
'net' : {
'image': 'busybox:latest',
'command': ["/bin/sleep", "300"]
},
'app': {
'image': 'busybox:latest',
'command': ["/bin/sleep", "300"],
'net': 'container:net'
},
'web': {
'image': 'busybox:latest',
'command': ["/bin/sleep", "300"],
'net': 'container:net',
'links': ['app']
},
},
client=self.client,
)
project.start()
self.assertEqual(len(project.containers()), 0)
project.up(['web'], start_links=False)
self.assertEqual(len(project.containers()), 1)
self.assertEqual(len(web.containers()), 1)
self.assertEqual(len(db.containers()), 0)
self.assertEqual(len(console.containers()), 0)
project.up(['web'])
self.assertEqual(len(project.containers()), 3)
self.assertEqual(len(project.get_service('web').containers()), 1)
self.assertEqual(len(project.get_service('app').containers()), 1)
self.assertEqual(len(project.get_service('net').containers()), 1)
self.assertEqual(len(project.get_service('console').containers()), 0)
project.kill()
project.remove_stopped()
def test_project_up_with_no_deps(self):
project = Project.from_config(
name='composetest',
config={
'console': {
'image': 'busybox:latest',
'command': ["/bin/sleep", "300"],
},
'net' : {
'image': 'busybox:latest',
'command': ["/bin/sleep", "300"]
},
'vol': {
'image': 'busybox:latest',
'command': ["/bin/sleep", "300"],
'volumes': ["/tmp"]
},
'app': {
'image': 'busybox:latest',
'command': ["/bin/sleep", "300"],
'net': 'container:net'
},
'web': {
'image': 'busybox:latest',
'command': ["/bin/sleep", "300"],
'net': 'container:net',
'links': ['app'],
'volumes_from': ['vol']
},
},
client=self.client,
)
project.start()
self.assertEqual(len(project.containers()), 0)
project.up(['web'], start_deps=False)
self.assertEqual(len(project.containers(stopped=True)), 2)
self.assertEqual(len(project.get_service('web').containers()), 1)
self.assertEqual(len(project.get_service('vol').containers(stopped=True)), 1)
self.assertEqual(len(project.get_service('net').containers()), 0)
self.assertEqual(len(project.get_service('console').containers()), 0)
project.kill()
project.remove_stopped()

View file

@ -2,6 +2,10 @@ from __future__ import unicode_literals
from .. import unittest
from compose.service import Service
from compose.project import Project, ConfigurationError
from compose.container import Container
import mock
import docker
class ProjectTest(unittest.TestCase):
def test_from_dict(self):
@ -120,7 +124,7 @@ class ProjectTest(unittest.TestCase):
)
project = Project('test', [web, db, cache, console], None)
self.assertEqual(
project.get_services(['console'], include_links=True),
project.get_services(['console'], include_deps=True),
[db, web, console]
)
@ -136,6 +140,105 @@ class ProjectTest(unittest.TestCase):
)
project = Project('test', [web, db], None)
self.assertEqual(
project.get_services(['web', 'db'], include_links=True),
project.get_services(['web', 'db'], include_deps=True),
[db, web]
)
def test_use_volumes_from_container(self):
container_id = 'aabbccddee'
container_dict = dict(Name='aaa', Id=container_id)
mock_client = mock.create_autospec(docker.Client)
mock_client.inspect_container.return_value = container_dict
project = Project.from_dicts('test', [
{
'name': 'test',
'image': 'busybox:latest',
'volumes_from': ['aaa']
}
], mock_client)
self.assertEqual(project.get_service('test')._get_volumes_from(), [container_id])
def test_use_volumes_from_service_no_container(self):
container_name = 'test_vol_1'
mock_client = mock.create_autospec(docker.Client)
mock_client.containers.return_value = [
{
"Name": container_name,
"Names": [container_name],
"Id": container_name,
"Image": 'busybox:latest'
}
]
project = Project.from_dicts('test', [
{
'name': 'vol',
'image': 'busybox:latest'
},
{
'name': 'test',
'image': 'busybox:latest',
'volumes_from': ['vol']
}
], mock_client)
self.assertEqual(project.get_service('test')._get_volumes_from(), [container_name])
@mock.patch.object(Service, 'containers')
def test_use_volumes_from_service_container(self, mock_return):
container_ids = ['aabbccddee', '12345']
mock_return.return_value = [
mock.Mock(id=container_id, spec=Container)
for container_id in container_ids]
project = Project.from_dicts('test', [
{
'name': 'vol',
'image': 'busybox:latest'
},
{
'name': 'test',
'image': 'busybox:latest',
'volumes_from': ['vol']
}
], None)
self.assertEqual(project.get_service('test')._get_volumes_from(), container_ids)
def test_use_net_from_container(self):
container_id = 'aabbccddee'
container_dict = dict(Name='aaa', Id=container_id)
mock_client = mock.create_autospec(docker.Client)
mock_client.inspect_container.return_value = container_dict
project = Project.from_dicts('test', [
{
'name': 'test',
'image': 'busybox:latest',
'net': 'container:aaa'
}
], mock_client)
service = project.get_service('test')
self.assertEqual(service._get_net(), 'container:'+container_id)
def test_use_net_from_service(self):
container_name = 'test_aaa_1'
mock_client = mock.create_autospec(docker.Client)
mock_client.containers.return_value = [
{
"Name": container_name,
"Names": [container_name],
"Id": container_name,
"Image": 'busybox:latest'
}
]
project = Project.from_dicts('test', [
{
'name': 'aaa',
'image': 'busybox:latest'
},
{
'name': 'test',
'image': 'busybox:latest',
'net': 'container:aaa'
}
], mock_client)
service = project.get_service('test')
self.assertEqual(service._get_net(), 'container:'+container_name)

View file

@ -65,6 +65,95 @@ class SortServiceTest(unittest.TestCase):
self.assertEqual(sorted_services[1]['name'], 'parent')
self.assertEqual(sorted_services[2]['name'], 'grandparent')
def test_sort_service_dicts_4(self):
services = [
{
'name': 'child'
},
{
'name': 'parent',
'volumes_from': ['child']
},
{
'links': ['parent'],
'name': 'grandparent'
},
]
sorted_services = sort_service_dicts(services)
self.assertEqual(len(sorted_services), 3)
self.assertEqual(sorted_services[0]['name'], 'child')
self.assertEqual(sorted_services[1]['name'], 'parent')
self.assertEqual(sorted_services[2]['name'], 'grandparent')
def test_sort_service_dicts_5(self):
services = [
{
'links': ['parent'],
'name': 'grandparent'
},
{
'name': 'parent',
'net': 'container:child'
},
{
'name': 'child'
}
]
sorted_services = sort_service_dicts(services)
self.assertEqual(len(sorted_services), 3)
self.assertEqual(sorted_services[0]['name'], 'child')
self.assertEqual(sorted_services[1]['name'], 'parent')
self.assertEqual(sorted_services[2]['name'], 'grandparent')
def test_sort_service_dicts_6(self):
services = [
{
'links': ['parent'],
'name': 'grandparent'
},
{
'name': 'parent',
'volumes_from': ['child']
},
{
'name': 'child'
}
]
sorted_services = sort_service_dicts(services)
self.assertEqual(len(sorted_services), 3)
self.assertEqual(sorted_services[0]['name'], 'child')
self.assertEqual(sorted_services[1]['name'], 'parent')
self.assertEqual(sorted_services[2]['name'], 'grandparent')
def test_sort_service_dicts_7(self):
services = [
{
'net': 'container:three',
'name': 'four'
},
{
'links': ['two'],
'name': 'three'
},
{
'name': 'two',
'volumes_from': ['one']
},
{
'name': 'one'
}
]
sorted_services = sort_service_dicts(services)
self.assertEqual(len(sorted_services), 4)
self.assertEqual(sorted_services[0]['name'], 'one')
self.assertEqual(sorted_services[1]['name'], 'two')
self.assertEqual(sorted_services[2]['name'], 'three')
self.assertEqual(sorted_services[3]['name'], 'four')
def test_sort_service_dicts_circular_imports(self):
services = [
{