service_test.py 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. from __future__ import unicode_literals
  2. from __future__ import absolute_import
  3. import os
  4. from .. import unittest
  5. import mock
  6. from fig import Service
  7. from fig.container import Container
  8. from fig.service import (
  9. ConfigError,
  10. split_port,
  11. parse_volume_spec,
  12. build_volume_binding,
  13. )
  14. class ServiceTest(unittest.TestCase):
  15. def test_name_validations(self):
  16. self.assertRaises(ConfigError, lambda: Service(name=''))
  17. self.assertRaises(ConfigError, lambda: Service(name=' '))
  18. self.assertRaises(ConfigError, lambda: Service(name='/'))
  19. self.assertRaises(ConfigError, lambda: Service(name='!'))
  20. self.assertRaises(ConfigError, lambda: Service(name='\xe2'))
  21. self.assertRaises(ConfigError, lambda: Service(name='_'))
  22. self.assertRaises(ConfigError, lambda: Service(name='____'))
  23. self.assertRaises(ConfigError, lambda: Service(name='foo_bar'))
  24. self.assertRaises(ConfigError, lambda: Service(name='__foo_bar__'))
  25. Service('a')
  26. Service('foo')
  27. def test_project_validation(self):
  28. self.assertRaises(ConfigError, lambda: Service(name='foo', project='_'))
  29. Service(name='foo', project='bar')
  30. def test_config_validation(self):
  31. self.assertRaises(ConfigError, lambda: Service(name='foo', port=['8000']))
  32. Service(name='foo', ports=['8000'])
  33. def test_get_volumes_from_container(self):
  34. container_id = 'aabbccddee'
  35. service = Service(
  36. 'test',
  37. volumes_from=[mock.Mock(id=container_id, spec=Container)])
  38. self.assertEqual(service._get_volumes_from(), [container_id])
  39. def test_get_volumes_from_intermediate_container(self):
  40. container_id = 'aabbccddee'
  41. service = Service('test')
  42. container = mock.Mock(id=container_id, spec=Container)
  43. self.assertEqual(service._get_volumes_from(container), [container_id])
  44. def test_get_volumes_from_service_container_exists(self):
  45. container_ids = ['aabbccddee', '12345']
  46. from_service = mock.create_autospec(Service)
  47. from_service.containers.return_value = [
  48. mock.Mock(id=container_id, spec=Container)
  49. for container_id in container_ids
  50. ]
  51. service = Service('test', volumes_from=[from_service])
  52. self.assertEqual(service._get_volumes_from(), container_ids)
  53. def test_get_volumes_from_service_no_container(self):
  54. container_id = 'abababab'
  55. from_service = mock.create_autospec(Service)
  56. from_service.containers.return_value = []
  57. from_service.create_container.return_value = mock.Mock(
  58. id=container_id,
  59. spec=Container)
  60. service = Service('test', volumes_from=[from_service])
  61. self.assertEqual(service._get_volumes_from(), [container_id])
  62. from_service.create_container.assert_called_once_with()
  63. def test_split_port_with_host_ip(self):
  64. internal_port, external_port = split_port("127.0.0.1:1000:2000")
  65. self.assertEqual(internal_port, "2000")
  66. self.assertEqual(external_port, ("127.0.0.1", "1000"))
  67. def test_split_port_with_protocol(self):
  68. internal_port, external_port = split_port("127.0.0.1:1000:2000/udp")
  69. self.assertEqual(internal_port, "2000/udp")
  70. self.assertEqual(external_port, ("127.0.0.1", "1000"))
  71. def test_split_port_with_host_ip_no_port(self):
  72. internal_port, external_port = split_port("127.0.0.1::2000")
  73. self.assertEqual(internal_port, "2000")
  74. self.assertEqual(external_port, ("127.0.0.1", None))
  75. def test_split_port_with_host_port(self):
  76. internal_port, external_port = split_port("1000:2000")
  77. self.assertEqual(internal_port, "2000")
  78. self.assertEqual(external_port, "1000")
  79. def test_split_port_no_host_port(self):
  80. internal_port, external_port = split_port("2000")
  81. self.assertEqual(internal_port, "2000")
  82. self.assertEqual(external_port, None)
  83. def test_split_port_invalid(self):
  84. with self.assertRaises(ConfigError):
  85. split_port("0.0.0.0:1000:2000:tcp")
  86. def test_split_domainname_none(self):
  87. service = Service('foo',
  88. hostname = 'name',
  89. )
  90. service.next_container_name = lambda x: 'foo'
  91. opts = service._get_container_create_options({})
  92. self.assertEqual(opts['hostname'], 'name', 'hostname')
  93. self.assertFalse('domainname' in opts, 'domainname')
  94. def test_split_domainname_fqdn(self):
  95. service = Service('foo',
  96. hostname = 'name.domain.tld',
  97. )
  98. service.next_container_name = lambda x: 'foo'
  99. opts = service._get_container_create_options({})
  100. self.assertEqual(opts['hostname'], 'name', 'hostname')
  101. self.assertEqual(opts['domainname'], 'domain.tld', 'domainname')
  102. def test_split_domainname_both(self):
  103. service = Service('foo',
  104. hostname = 'name',
  105. domainname = 'domain.tld',
  106. )
  107. service.next_container_name = lambda x: 'foo'
  108. opts = service._get_container_create_options({})
  109. self.assertEqual(opts['hostname'], 'name', 'hostname')
  110. self.assertEqual(opts['domainname'], 'domain.tld', 'domainname')
  111. def test_split_domainname_weird(self):
  112. service = Service('foo',
  113. hostname = 'name.sub',
  114. domainname = 'domain.tld',
  115. )
  116. service.next_container_name = lambda x: 'foo'
  117. opts = service._get_container_create_options({})
  118. self.assertEqual(opts['hostname'], 'name.sub', 'hostname')
  119. self.assertEqual(opts['domainname'], 'domain.tld', 'domainname')
  120. class ServiceVolumesTest(unittest.TestCase):
  121. def test_parse_volume_spec_only_one_path(self):
  122. spec = parse_volume_spec('/the/volume')
  123. self.assertEqual(spec, (None, '/the/volume', 'rw'))
  124. def test_parse_volume_spec_internal_and_external(self):
  125. spec = parse_volume_spec('external:interval')
  126. self.assertEqual(spec, ('external', 'interval', 'rw'))
  127. def test_parse_volume_spec_with_mode(self):
  128. spec = parse_volume_spec('external:interval:ro')
  129. self.assertEqual(spec, ('external', 'interval', 'ro'))
  130. def test_parse_volume_spec_too_many_parts(self):
  131. with self.assertRaises(ConfigError):
  132. parse_volume_spec('one:two:three:four')
  133. def test_parse_volume_bad_mode(self):
  134. with self.assertRaises(ConfigError):
  135. parse_volume_spec('one:two:notrw')
  136. def test_build_volume_binding(self):
  137. binding = build_volume_binding(parse_volume_spec('/outside:/inside'))
  138. self.assertEqual(
  139. binding,
  140. ('/outside', dict(bind='/inside', ro=False)))
  141. @mock.patch.dict(os.environ)
  142. def test_build_volume_binding_with_environ(self):
  143. os.environ['VOLUME_PATH'] = '/opt'
  144. binding = build_volume_binding(parse_volume_spec('${VOLUME_PATH}:/opt'))
  145. self.assertEqual(binding, ('/opt', dict(bind='/opt', ro=False)))
  146. @mock.patch.dict(os.environ)
  147. def test_building_volume_binding_with_home(self):
  148. os.environ['HOME'] = '/home/user'
  149. binding = build_volume_binding(parse_volume_spec('~:/home/user'))
  150. self.assertEqual(
  151. binding,
  152. ('/home/user', dict(bind='/home/user', ro=False)))