def test_create_container(self): service = Service('foo', client=self.mock_client, build={'context': '.'}) self.mock_client.inspect_image.side_effect = [ NoSuchImageError, {'Id': 'abc123'}, ] self.mock_client.build.return_value = [ '{"stream": "Successfully built abcd"}', ] with mock.patch('compose.service.log', autospec=True) as mock_log: service.create_container() assert mock_log.warn.called _, args, _ = mock_log.warn.mock_calls[0] assert 'was built because it did not already exist' in args[0] self.mock_client.build.assert_called_once_with( tag='default_foo', dockerfile=None, stream=True, path='.', pull=False, forcerm=False, nocache=False, rm=True, buildargs=None, )
def test_get_container_create_options_with_healthcheck(self): service = Service( 'foo', image='foo', client=self.mock_client, healthcheck={ 'retries': 3, 'command': 'exit 0', 'timeout': '5s', 'interval': '10s' } ) self.mock_client.inspect_image.return_value = {'Id': 'abcd'} prev_container = mock.Mock( id='ababab', image_config={'ContainerConfig': {}}) prev_container.get.return_value = None opts = service._get_container_create_options( {}, 1, previous_container=prev_container) assert opts['healthcheck'] == { 'Retries': 3, 'Interval': 10000000000, 'Test': ['CMD-SHELL', 'exit 0'], 'Timeout': 5000000000 }
def test_pull_image_no_tag(self): service = Service('foo', client=self.mock_client, image='ababab') service.pull() self.mock_client.pull.assert_called_once_with( 'ababab', tag='latest', stream=True)
def test_connect_container_to_networks_short_aliase_exists(self): mock_client = mock.create_autospec(docker.Client) service = Service( 'db', mock_client, 'myproject', image='foo', networks={'project_default': {}}) container = Container( None, { 'Id': 'abcdef', 'NetworkSettings': { 'Networks': { 'project_default': { 'Aliases': ['analias', 'abcdef'], }, }, }, }, True) service.connect_container_to_networks(container) assert not mock_client.disconnect_container_from_network.call_count assert not mock_client.connect_container_to_network.call_count
def test_recreate_container_with_timeout(self, _): mock_container = mock.create_autospec(Container) self.mock_client.inspect_image.return_value = {'Id': 'abc123'} service = Service('foo', client=self.mock_client, image='someimage') service.recreate_container(mock_container, timeout=1) mock_container.stop.assert_called_once_with(timeout=1)
def test_mount_same_host_path_to_two_volumes(self): service = Service( 'web', image='busybox', volumes=[ '/host/path:/data1', '/host/path:/data2', ], client=self.mock_client, ) self.mock_client.inspect_image.return_value = { 'Id': 'ababab', 'ContainerConfig': { 'Volumes': {} } } create_options = service._get_container_create_options( override_options={}, number=1, ) self.assertEqual( set(create_options['host_config']['Binds']), set([ '/host/path:/data1:rw', '/host/path:/data2:rw', ]), )
def test_different_host_path_in_container_json(self): service = Service( 'web', image='busybox', volumes=['/host/path:/data'], client=self.mock_client, ) self.mock_client.inspect_image.return_value = { 'Id': 'ababab', 'ContainerConfig': { 'Volumes': { '/data': {}, } } } self.mock_client.inspect_container.return_value = { 'Id': '123123123', 'Image': 'ababab', 'Volumes': { '/data': '/mnt/sda1/host/path', }, } create_options = service._get_container_create_options( override_options={}, number=1, previous_container=Container(self.mock_client, {'Id': '123123123'}), ) self.assertEqual( create_options['host_config']['Binds'], ['/mnt/sda1/host/path:/data:rw'], )
def test_get_container_create_options_sets_affinity_with_binds(self): service = Service( 'foo', image='foo', client=self.mock_client, ) self.mock_client.inspect_image.return_value = {'Id': 'abcd'} prev_container = mock.Mock( id='ababab', image_config={'ContainerConfig': {'Volumes': ['/data']}}) def container_get(key): return { 'Mounts': [ { 'Destination': '/data', 'Source': '/some/path', 'Name': 'abab1234', }, ] }.get(key, None) prev_container.get.side_effect = container_get opts = service._get_container_create_options( {}, 1, previous_container=prev_container) assert opts['environment'] == ['affinity:container==ababab']
def test_get_container_create_options_does_not_mutate_options(self): labels = {'thing': 'real'} environment = {'also': 'real'} service = Service( 'foo', image='foo', labels=dict(labels), client=self.mock_client, environment=dict(environment), ) self.mock_client.inspect_image.return_value = {'Id': 'abcd'} prev_container = mock.Mock( id='ababab', image_config={'ContainerConfig': {}}) prev_container.get.return_value = None opts = service._get_container_create_options( {}, 1, previous_container=prev_container) self.assertEqual(service.options['labels'], labels) self.assertEqual(service.options['environment'], environment) self.assertEqual( opts['labels'][LABEL_CONFIG_HASH], '2524a06fcb3d781aa2c981fc40bcfa08013bb318e4273bfa388df22023e6f2aa') assert opts['environment'] == ['also=real']
def test_ensure_image_exists_force_build(self): service = Service('foo', client=self.mock_client, build={'context': '.'}) self.mock_client.inspect_image.return_value = {'Id': 'abc123'} self.mock_client.build.return_value = [ '{"stream": "Successfully built abcd"}', ] with mock.patch('compose.service.log', autospec=True) as mock_log: service.ensure_image_exists(do_build=BuildAction.force) assert not mock_log.warn.called self.mock_client.build.assert_called_once_with( tag='default_foo', dockerfile=None, stream=True, path='.', pull=False, forcerm=False, nocache=False, rm=True, buildargs={}, labels=None, cache_from=None, network_mode=None, target=None, )
def test_self_reference_external_link(self): service = Service( name='foo', external_links=['default_foo_1'] ) with self.assertRaises(DependencyError): service.get_container_name(1)
def test_execute_convergence_plan_when_image_volume_masks_config(self): service = Service( project='composetest', name='db', client=self.client, build='tests/fixtures/dockerfile-with-volume', ) old_container = create_and_start_container(service) self.assertEqual(list(old_container.get('Volumes').keys()), ['/data']) volume_path = old_container.get('Volumes')['/data'] service.options['volumes'] = ['/tmp:/data'] with mock.patch('compose.service.log') as mock_log: new_container, = service.execute_convergence_plan( ConvergencePlan('recreate', [old_container])) mock_log.warn.assert_called_once_with(mock.ANY) _, args, kwargs = mock_log.warn.mock_calls[0] self.assertIn( "Service \"db\" is using volume \"/data\" from the previous container", args[0]) self.assertEqual(list(new_container.get('Volumes')), ['/data']) self.assertEqual(new_container.get('Volumes')['/data'], volume_path)
def test_mount_same_host_path_to_two_volumes(self): service = Service( 'web', image='busybox', volumes=[ VolumeSpec.parse('/host/path:/data1', True), VolumeSpec.parse('/host/path:/data2', True), ], client=self.mock_client, ) self.mock_client.inspect_image.return_value = { 'Id': 'ababab', 'ContainerConfig': { 'Volumes': {} } } service._get_container_create_options( override_options={}, number=1, ) assert set(self.mock_client.create_host_config.call_args[1]['binds']) == set([ '/host/path:/data1:rw', '/host/path:/data2:rw', ])
def test_get_volumes_from_container_read_only(self): container_id = "aabbccddee" service = Service( "test", image="foo", volumes_from=[VolumeFromSpec(mock.Mock(id=container_id, spec=Container), "ro")] ) self.assertEqual(service._get_volumes_from(), [container_id + ":ro"])
def test_get_container_create_options_does_not_mutate_options(self): labels = {'thing': 'real'} environment = {'also': 'real'} service = Service( 'foo', image='foo', labels=dict(labels), client=self.mock_client, environment=dict(environment), ) self.mock_client.inspect_image.return_value = {'Id': 'abcd'} prev_container = mock.Mock( id='ababab', image_config={'ContainerConfig': {}}) opts = service._get_container_create_options( {}, 1, previous_container=prev_container) self.assertEqual(service.options['labels'], labels) self.assertEqual(service.options['environment'], environment) self.assertEqual( opts['labels'][LABEL_CONFIG_HASH], 'b30306d0a73b67f67a45b99b88d36c359e470e6fa0c04dda1cf62d2087205b81') self.assertEqual( opts['environment'], { 'affinity:container': '=ababab', 'also': 'real', } )
def test_recreate_container_with_timeout(self, _): mock_container = mock.create_autospec(Container) self.mock_client.inspect_image.return_value = {"Id": "abc123"} service = Service("foo", client=self.mock_client, image="someimage") service.recreate_container(mock_container, timeout=1) mock_container.stop.assert_called_once_with(timeout=1)
def test_get_container_create_options_does_not_mutate_options(self): labels = {'thing': 'real'} environment = {'also': 'real'} service = Service( 'foo', image='foo', labels=dict(labels), client=self.mock_client, environment=dict(environment), ) self.mock_client.inspect_image.return_value = {'Id': 'abcd'} prev_container = mock.Mock( id='ababab', image_config={'ContainerConfig': {}}) prev_container.get.return_value = None opts = service._get_container_create_options( {}, 1, previous_container=prev_container) self.assertEqual(service.options['labels'], labels) self.assertEqual(service.options['environment'], environment) self.assertEqual( opts['labels'][LABEL_CONFIG_HASH], 'f8bfa1058ad1f4231372a0b1639f0dfdb574dafff4e8d7938049ae993f7cf1fc') assert opts['environment'] == ['also=real']
def test_get_container_create_options_does_not_mutate_options(self): labels = {'thing': 'real'} environment = {'also': 'real'} service = Service( 'foo', image='foo', labels=dict(labels), client=self.mock_client, environment=dict(environment), ) self.mock_client.inspect_image.return_value = {'Id': 'abcd'} prev_container = mock.Mock( id='ababab', image_config={'ContainerConfig': {}}) opts = service._get_container_create_options( {}, 1, previous_container=prev_container) self.assertEqual(service.options['labels'], labels) self.assertEqual(service.options['environment'], environment) self.assertEqual( opts['labels'][LABEL_CONFIG_HASH], '3c85881a8903b9d73a06c41860c8be08acce1494ab4cf8408375966dccd714de') self.assertEqual( opts['environment'], { 'affinity:container': '=ababab', 'also': 'real', } )
def test_get_links_with_networking(self): service = Service( 'foo', image='foo', links=[(Service('one'), 'one')], use_networking=True) self.assertEqual(service._get_links(link_to_self=True), [])
def test_get_container(self, mock_container_class): container_dict = dict(Name="default_foo_2") self.mock_client.containers.return_value = [container_dict] service = Service("foo", image="foo", client=self.mock_client) container = service.get_container(number=2) self.assertEqual(container, mock_container_class.from_ps.return_value) mock_container_class.from_ps.assert_called_once_with(self.mock_client, container_dict)
def test_cgroup_parent(self): self.mock_client.create_host_config.return_value = {} service = Service(name="foo", image="foo", hostname="name", client=self.mock_client, cgroup_parent="test") service._get_container_create_options({"some": "overrides"}, 1) self.assertTrue(self.mock_client.create_host_config.called) self.assertEqual(self.mock_client.create_host_config.call_args[1]["cgroup_parent"], "test")
def test_get_volumes_from_container(self): container_id = 'aabbccddee' service = Service( 'test', image='foo', volumes_from=[mock.Mock(id=container_id, spec=Container)]) self.assertEqual(service._get_volumes_from(), [container_id])
def test_log_opt(self): log_opt = {'syslog-address': 'tcp://192.168.0.42:123'} service = Service(name='foo', image='foo', hostname='name', client=self.mock_client, log_driver='syslog', log_opt=log_opt) opts = service._get_container_create_options({'some': 'overrides'}, 1) self.assertIsInstance(opts['host_config']['LogConfig'], LogConfig) self.assertEqual(opts['host_config']['LogConfig'].type, 'syslog') self.assertEqual(opts['host_config']['LogConfig'].config, log_opt)
def test_build_does_not_pull(self): self.mock_client.build.return_value = ['{"stream": "Successfully built 12345"}'] service = Service("foo", client=self.mock_client, build=".") service.build() self.assertEqual(self.mock_client.build.call_count, 1) self.assertFalse(self.mock_client.build.call_args[1]["pull"])
def test_pull_image(self, mock_log): service = Service('foo', client=self.mock_client, image='someimage:sometag') service.pull() self.mock_client.pull.assert_called_once_with( 'someimage', tag='sometag', stream=True) mock_log.info.assert_called_once_with('Pulling foo (someimage:sometag)...')
def test_get_volumes_from_container_read_only(self): container_id = 'aabbccddee' service = Service( 'test', image='foo', volumes_from=[VolumeFromSpec(mock.Mock(id=container_id, spec=Container), 'ro')]) self.assertEqual(service._get_volumes_from(), [container_id + ':ro'])
def test_get_volumes_from_service_no_container(self): container_id = "abababab" from_service = mock.create_autospec(Service) from_service.containers.return_value = [] from_service.create_container.return_value = mock.Mock(id=container_id, spec=Container) service = Service("test", image="foo", volumes_from=[from_service]) self.assertEqual(service._get_volumes_from(), [container_id]) from_service.create_container.assert_called_once_with()
def test_split_domainname_fqdn(self): service = Service( 'foo', hostname='name.domain.tld', image='foo', client=self.mock_client) opts = service._get_container_create_options({'image': 'foo'}, 1) self.assertEqual(opts['hostname'], 'name', 'hostname') self.assertEqual(opts['domainname'], 'domain.tld', 'domainname')
def test_no_default_hostname_when_not_using_networking(self): service = Service( 'foo', image='foo', use_networking=False, client=self.mock_client, ) opts = service._get_container_create_options({'image': 'foo'}, 1) self.assertIsNone(opts.get('hostname'))
def test_create_container_with_build(self): service = Service('foo', client=self.mock_client, build='.') images = [] service.image = lambda *args, **kwargs: mock_get_image(images) service.build = lambda: images.append({'Id': 'abc123'}) service.create_container(do_build=True) self.assertEqual(1, len(images))
def test_remove_image_local_without_image_name_does_remove(self): web = Service('web', build='.', client=self.mock_client) assert web.remove_image(ImageType.local) self.mock_client.remove_image.assert_called_once_with(web.image_name)
def test_remove_image_all_does_remove(self): web = Service('web', image='example', client=self.mock_client) assert web.remove_image(ImageType.all) self.mock_client.remove_image.assert_called_once_with(web.image_name)
def test_memory_swap_limit(self): service = Service(name='foo', image='foo', hostname='name', client=self.mock_client, mem_limit=1000000000, memswap_limit=2000000000) self.mock_client.containers.return_value = [] opts = service._get_container_create_options({'some': 'overrides'}, 1) self.assertEqual(opts['host_config']['MemorySwap'], 2000000000) self.assertEqual(opts['host_config']['Memory'], 1000000000)
def test_specifies_host_port_with_no_ports(self): service = Service('foo', image='foo') self.assertEqual(service.specifies_host_port(), False)
def test_specifies_host_port_with_host_port(self): service = Service('foo', image='foo', ports=["1000:2000"]) self.assertEqual(service.specifies_host_port(), True)
def test_specifies_host_port_with_host_ip_no_port(self): service = Service('foo', image='foo', ports=["127.0.0.1::2000"]) self.assertEqual(service.specifies_host_port(), False)
def test_specifies_host_port_with_container_port_range(self): service = Service('foo', image='foo', ports=["2000-3000"]) self.assertEqual(service.specifies_host_port(), False)
def test_containers(self): service = Service('db', self.mock_client, 'myproject', image='foo') self.mock_client.containers.return_value = [] self.assertEqual(list(service.containers()), [])
def test_remove_image_none(self): web = Service('web', image='example', client=self.mock_client) assert not web.remove_image(ImageType.none) assert not self.mock_client.remove_image.called
def test_split_domainname_none(self): service = Service('foo', image='foo', hostname='name', client=self.mock_client) self.mock_client.containers.return_value = [] opts = service._get_container_create_options({'image': 'foo'}, 1) self.assertEqual(opts['hostname'], 'name', 'hostname') self.assertFalse('domainname' in opts, 'domainname')
def test_image_name_default(self): service = Service('foo', project='testing') assert service.image_name == 'testing_foo'
def test_image_name_from_config(self): image_name = 'example/web:latest' service = Service('foo', image=image_name) assert service.image_name == image_name
def test_remove_image_local_with_image_name_doesnt_remove(self): web = Service('web', image='example', client=self.mock_client) assert not web.remove_image(ImageType.local) assert not self.mock_client.remove_image.called
def test_specifies_host_port_with_host_ip_and_port_range(self): service = Service('foo', image='foo', ports=["127.0.0.1:1000-2000:2000-3000"]) self.assertEqual(service.specifies_host_port(), True)
def test_pull_image_no_tag(self): service = Service('foo', client=self.mock_client, image='ababab') service.pull() self.mock_client.pull.assert_called_once_with('ababab', tag='latest', stream=True)
def test_get_container_not_found(self): self.mock_client.containers.return_value = [] service = Service('foo', client=self.mock_client, image='foo') self.assertRaises(ValueError, service.get_container)