forked from docker/docs
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add some unit tests for new bundle and push commands.
Signed-off-by: Daniel Nephin <dnephin@docker.com>
- Loading branch information
Showing
3 changed files
with
270 additions
and
20 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,232 @@ | ||
from __future__ import absolute_import | ||
from __future__ import unicode_literals | ||
|
||
import docker | ||
import mock | ||
import pytest | ||
|
||
from compose import bundle | ||
from compose import service | ||
from compose.cli.errors import UserError | ||
from compose.config.config import Config | ||
|
||
|
||
@pytest.fixture | ||
def mock_service(): | ||
return mock.create_autospec( | ||
service.Service, | ||
client=mock.create_autospec(docker.Client), | ||
options={}) | ||
|
||
|
||
def test_get_image_digest_exists(mock_service): | ||
mock_service.options['image'] = 'abcd' | ||
mock_service.image.return_value = {'RepoDigests': ['digest1']} | ||
digest = bundle.get_image_digest(mock_service) | ||
assert digest == 'digest1' | ||
|
||
|
||
def test_get_image_digest_image_uses_digest(mock_service): | ||
mock_service.options['image'] = image_id = 'redis@sha256:digest' | ||
|
||
digest = bundle.get_image_digest(mock_service) | ||
assert digest == image_id | ||
assert not mock_service.image.called | ||
|
||
|
||
def test_get_image_digest_no_image(mock_service): | ||
with pytest.raises(UserError) as exc: | ||
bundle.get_image_digest(service.Service(name='theservice')) | ||
|
||
assert "doesn't define an image tag" in exc.exconly() | ||
|
||
|
||
def test_fetch_image_digest_for_image_with_saved_digest(mock_service): | ||
mock_service.options['image'] = image_id = 'abcd' | ||
mock_service.pull.return_value = expected = 'sha256:thedigest' | ||
mock_service.image.return_value = {'RepoDigests': ['digest1']} | ||
|
||
digest = bundle.fetch_image_digest(mock_service) | ||
assert digest == image_id + '@' + expected | ||
|
||
mock_service.pull.assert_called_once_with() | ||
assert not mock_service.push.called | ||
assert not mock_service.client.pull.called | ||
|
||
|
||
def test_fetch_image_digest_for_image(mock_service): | ||
mock_service.options['image'] = image_id = 'abcd' | ||
mock_service.pull.return_value = expected = 'sha256:thedigest' | ||
mock_service.image.return_value = {'RepoDigests': []} | ||
|
||
digest = bundle.fetch_image_digest(mock_service) | ||
assert digest == image_id + '@' + expected | ||
|
||
mock_service.pull.assert_called_once_with() | ||
assert not mock_service.push.called | ||
mock_service.client.pull.assert_called_once_with(digest) | ||
|
||
|
||
def test_fetch_image_digest_for_build(mock_service): | ||
mock_service.options['build'] = '.' | ||
mock_service.options['image'] = image_id = 'abcd' | ||
mock_service.push.return_value = expected = 'sha256:thedigest' | ||
mock_service.image.return_value = {'RepoDigests': ['digest1']} | ||
|
||
digest = bundle.fetch_image_digest(mock_service) | ||
assert digest == image_id + '@' + expected | ||
|
||
mock_service.push.assert_called_once_with() | ||
assert not mock_service.pull.called | ||
assert not mock_service.client.pull.called | ||
|
||
|
||
def test_to_bundle(): | ||
image_digests = {'a': 'aaaa', 'b': 'bbbb'} | ||
services = [ | ||
{'name': 'a', 'build': '.', }, | ||
{'name': 'b', 'build': './b'}, | ||
] | ||
config = Config( | ||
version=2, | ||
services=services, | ||
volumes={'special': {}}, | ||
networks={'extra': {}}) | ||
|
||
with mock.patch('compose.bundle.log.warn', autospec=True) as mock_log: | ||
output = bundle.to_bundle(config, image_digests) | ||
|
||
assert mock_log.mock_calls == [ | ||
mock.call("Unsupported top level key 'networks' - ignoring"), | ||
mock.call("Unsupported top level key 'volumes' - ignoring"), | ||
] | ||
|
||
assert output == { | ||
'Version': '0.1', | ||
'Services': { | ||
'a': {'Image': 'aaaa', 'Networks': ['default']}, | ||
'b': {'Image': 'bbbb', 'Networks': ['default']}, | ||
} | ||
} | ||
|
||
|
||
def test_convert_service_to_bundle(): | ||
name = 'theservice' | ||
image_digest = 'thedigest' | ||
service_dict = { | ||
'ports': ['80'], | ||
'expose': ['1234'], | ||
'networks': {'extra': {}}, | ||
'command': 'foo', | ||
'entrypoint': 'entry', | ||
'environment': {'BAZ': 'ENV'}, | ||
'build': '.', | ||
'working_dir': '/tmp', | ||
'user': 'root', | ||
'labels': {'FOO': 'LABEL'}, | ||
'privileged': True, | ||
} | ||
|
||
with mock.patch('compose.bundle.log.warn', autospec=True) as mock_log: | ||
config = bundle.convert_service_to_bundle(name, service_dict, image_digest) | ||
|
||
mock_log.assert_called_once_with( | ||
"Unsupported key 'privileged' in services.theservice - ignoring") | ||
|
||
assert config == { | ||
'Image': image_digest, | ||
'Ports': [ | ||
{'Protocol': 'tcp', 'Port': 80}, | ||
{'Protocol': 'tcp', 'Port': 1234}, | ||
], | ||
'Networks': ['extra'], | ||
'Command': ['entry', 'foo'], | ||
'Env': ['BAZ=ENV'], | ||
'WorkingDir': '/tmp', | ||
'User': 'root', | ||
'Labels': {'FOO': 'LABEL'}, | ||
} | ||
|
||
|
||
def test_set_command_and_args_none(): | ||
config = {} | ||
bundle.set_command_and_args(config, [], []) | ||
assert config == {} | ||
|
||
|
||
def test_set_command_and_args_from_command(): | ||
config = {} | ||
bundle.set_command_and_args(config, [], "echo ok") | ||
assert config == {'Args': ['echo', 'ok']} | ||
|
||
|
||
def test_set_command_and_args_from_entrypoint(): | ||
config = {} | ||
bundle.set_command_and_args(config, "echo entry", []) | ||
assert config == {'Command': ['echo', 'entry']} | ||
|
||
|
||
def test_set_command_and_args_from_both(): | ||
config = {} | ||
bundle.set_command_and_args(config, "echo entry", ["extra", "arg"]) | ||
assert config == {'Command': ['echo', 'entry', "extra", "arg"]} | ||
|
||
|
||
def test_make_service_networks_default(): | ||
name = 'theservice' | ||
service_dict = {} | ||
|
||
with mock.patch('compose.bundle.log.warn', autospec=True) as mock_log: | ||
networks = bundle.make_service_networks(name, service_dict) | ||
|
||
assert not mock_log.called | ||
assert networks == ['default'] | ||
|
||
|
||
def test_make_service_networks(): | ||
name = 'theservice' | ||
service_dict = { | ||
'networks': { | ||
'foo': { | ||
'aliases': ['one', 'two'], | ||
}, | ||
'bar': {} | ||
}, | ||
} | ||
|
||
with mock.patch('compose.bundle.log.warn', autospec=True) as mock_log: | ||
networks = bundle.make_service_networks(name, service_dict) | ||
|
||
mock_log.assert_called_once_with( | ||
"Unsupported key 'aliases' in services.theservice.networks.foo - ignoring") | ||
assert sorted(networks) == sorted(service_dict['networks']) | ||
|
||
|
||
def test_make_port_specs(): | ||
service_dict = { | ||
'expose': ['80', '500/udp'], | ||
'ports': [ | ||
'400:80', | ||
'222', | ||
'127.0.0.1:8001:8001', | ||
'127.0.0.1:5000-5001:3000-3001'], | ||
} | ||
port_specs = bundle.make_port_specs(service_dict) | ||
assert port_specs == [ | ||
{'Protocol': 'tcp', 'Port': 80}, | ||
{'Protocol': 'tcp', 'Port': 222}, | ||
{'Protocol': 'tcp', 'Port': 8001}, | ||
{'Protocol': 'tcp', 'Port': 3000}, | ||
{'Protocol': 'tcp', 'Port': 3001}, | ||
{'Protocol': 'udp', 'Port': 500}, | ||
] | ||
|
||
|
||
def test_make_port_spec_with_protocol(): | ||
port_spec = bundle.make_port_spec("5000/udp") | ||
assert port_spec == {'Protocol': 'udp', 'Port': 5000} | ||
|
||
|
||
def test_make_port_spec_default_protocol(): | ||
port_spec = bundle.make_port_spec("50000") | ||
assert port_spec == {'Protocol': 'tcp', 'Port': 50000} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters