project_test.py 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297
  1. from __future__ import unicode_literals
  2. import docker
  3. from .. import mock
  4. from .. import unittest
  5. from compose.config.config import Config
  6. from compose.config.types import VolumeFromSpec
  7. from compose.const import LABEL_SERVICE
  8. from compose.container import Container
  9. from compose.project import Project
  10. from compose.service import ContainerNet
  11. from compose.service import Net
  12. from compose.service import Service
  13. class ProjectTest(unittest.TestCase):
  14. def setUp(self):
  15. self.mock_client = mock.create_autospec(docker.Client)
  16. def test_from_dict(self):
  17. project = Project.from_config('composetest', Config(None, [
  18. {
  19. 'name': 'web',
  20. 'image': 'busybox:latest'
  21. },
  22. {
  23. 'name': 'db',
  24. 'image': 'busybox:latest'
  25. },
  26. ], None), None)
  27. self.assertEqual(len(project.services), 2)
  28. self.assertEqual(project.get_service('web').name, 'web')
  29. self.assertEqual(project.get_service('web').options['image'], 'busybox:latest')
  30. self.assertEqual(project.get_service('db').name, 'db')
  31. self.assertEqual(project.get_service('db').options['image'], 'busybox:latest')
  32. def test_from_config(self):
  33. dicts = Config(None, [
  34. {
  35. 'name': 'web',
  36. 'image': 'busybox:latest',
  37. },
  38. {
  39. 'name': 'db',
  40. 'image': 'busybox:latest',
  41. },
  42. ], None)
  43. project = Project.from_config('composetest', dicts, None)
  44. self.assertEqual(len(project.services), 2)
  45. self.assertEqual(project.get_service('web').name, 'web')
  46. self.assertEqual(project.get_service('web').options['image'], 'busybox:latest')
  47. self.assertEqual(project.get_service('db').name, 'db')
  48. self.assertEqual(project.get_service('db').options['image'], 'busybox:latest')
  49. def test_get_service(self):
  50. web = Service(
  51. project='composetest',
  52. name='web',
  53. client=None,
  54. image="busybox:latest",
  55. )
  56. project = Project('test', [web], None)
  57. self.assertEqual(project.get_service('web'), web)
  58. def test_get_services_returns_all_services_without_args(self):
  59. web = Service(
  60. project='composetest',
  61. name='web',
  62. image='foo',
  63. )
  64. console = Service(
  65. project='composetest',
  66. name='console',
  67. image='foo',
  68. )
  69. project = Project('test', [web, console], None)
  70. self.assertEqual(project.get_services(), [web, console])
  71. def test_get_services_returns_listed_services_with_args(self):
  72. web = Service(
  73. project='composetest',
  74. name='web',
  75. image='foo',
  76. )
  77. console = Service(
  78. project='composetest',
  79. name='console',
  80. image='foo',
  81. )
  82. project = Project('test', [web, console], None)
  83. self.assertEqual(project.get_services(['console']), [console])
  84. def test_get_services_with_include_links(self):
  85. db = Service(
  86. project='composetest',
  87. name='db',
  88. image='foo',
  89. )
  90. web = Service(
  91. project='composetest',
  92. name='web',
  93. image='foo',
  94. links=[(db, 'database')]
  95. )
  96. cache = Service(
  97. project='composetest',
  98. name='cache',
  99. image='foo'
  100. )
  101. console = Service(
  102. project='composetest',
  103. name='console',
  104. image='foo',
  105. links=[(web, 'web')]
  106. )
  107. project = Project('test', [web, db, cache, console], None)
  108. self.assertEqual(
  109. project.get_services(['console'], include_deps=True),
  110. [db, web, console]
  111. )
  112. def test_get_services_removes_duplicates_following_links(self):
  113. db = Service(
  114. project='composetest',
  115. name='db',
  116. image='foo',
  117. )
  118. web = Service(
  119. project='composetest',
  120. name='web',
  121. image='foo',
  122. links=[(db, 'database')]
  123. )
  124. project = Project('test', [web, db], None)
  125. self.assertEqual(
  126. project.get_services(['web', 'db'], include_deps=True),
  127. [db, web]
  128. )
  129. def test_use_volumes_from_container(self):
  130. container_id = 'aabbccddee'
  131. container_dict = dict(Name='aaa', Id=container_id)
  132. self.mock_client.inspect_container.return_value = container_dict
  133. project = Project.from_config('test', Config(None, [
  134. {
  135. 'name': 'test',
  136. 'image': 'busybox:latest',
  137. 'volumes_from': [VolumeFromSpec('aaa', 'rw')]
  138. }
  139. ], None), self.mock_client)
  140. self.assertEqual(project.get_service('test')._get_volumes_from(), [container_id + ":rw"])
  141. def test_use_volumes_from_service_no_container(self):
  142. container_name = 'test_vol_1'
  143. self.mock_client.containers.return_value = [
  144. {
  145. "Name": container_name,
  146. "Names": [container_name],
  147. "Id": container_name,
  148. "Image": 'busybox:latest'
  149. }
  150. ]
  151. project = Project.from_config('test', Config(None, [
  152. {
  153. 'name': 'vol',
  154. 'image': 'busybox:latest'
  155. },
  156. {
  157. 'name': 'test',
  158. 'image': 'busybox:latest',
  159. 'volumes_from': [VolumeFromSpec('vol', 'rw')]
  160. }
  161. ], None), self.mock_client)
  162. self.assertEqual(project.get_service('test')._get_volumes_from(), [container_name + ":rw"])
  163. def test_use_volumes_from_service_container(self):
  164. container_ids = ['aabbccddee', '12345']
  165. project = Project.from_config('test', Config(None, [
  166. {
  167. 'name': 'vol',
  168. 'image': 'busybox:latest'
  169. },
  170. {
  171. 'name': 'test',
  172. 'image': 'busybox:latest',
  173. 'volumes_from': [VolumeFromSpec('vol', 'rw')]
  174. }
  175. ], None), None)
  176. with mock.patch.object(Service, 'containers') as mock_return:
  177. mock_return.return_value = [
  178. mock.Mock(id=container_id, spec=Container)
  179. for container_id in container_ids]
  180. self.assertEqual(
  181. project.get_service('test')._get_volumes_from(),
  182. [container_ids[0] + ':rw'])
  183. def test_net_unset(self):
  184. project = Project.from_config('test', Config(None, [
  185. {
  186. 'name': 'test',
  187. 'image': 'busybox:latest',
  188. }
  189. ], None), self.mock_client)
  190. service = project.get_service('test')
  191. self.assertEqual(service.net.id, None)
  192. self.assertNotIn('NetworkMode', service._get_container_host_config({}))
  193. def test_use_net_from_container(self):
  194. container_id = 'aabbccddee'
  195. container_dict = dict(Name='aaa', Id=container_id)
  196. self.mock_client.inspect_container.return_value = container_dict
  197. project = Project.from_config('test', Config(None, [
  198. {
  199. 'name': 'test',
  200. 'image': 'busybox:latest',
  201. 'net': 'container:aaa'
  202. }
  203. ], None), self.mock_client)
  204. service = project.get_service('test')
  205. self.assertEqual(service.net.mode, 'container:' + container_id)
  206. def test_use_net_from_service(self):
  207. container_name = 'test_aaa_1'
  208. self.mock_client.containers.return_value = [
  209. {
  210. "Name": container_name,
  211. "Names": [container_name],
  212. "Id": container_name,
  213. "Image": 'busybox:latest'
  214. }
  215. ]
  216. project = Project.from_config('test', Config(None, [
  217. {
  218. 'name': 'aaa',
  219. 'image': 'busybox:latest'
  220. },
  221. {
  222. 'name': 'test',
  223. 'image': 'busybox:latest',
  224. 'net': 'container:aaa'
  225. }
  226. ], None), self.mock_client)
  227. service = project.get_service('test')
  228. self.assertEqual(service.net.mode, 'container:' + container_name)
  229. def test_uses_default_network_true(self):
  230. web = Service('web', project='test', image="alpine", net=Net('test'))
  231. db = Service('web', project='test', image="alpine", net=Net('other'))
  232. project = Project('test', [web, db], None)
  233. assert project.uses_default_network()
  234. def test_uses_default_network_custom_name(self):
  235. web = Service('web', project='test', image="alpine", net=Net('other'))
  236. project = Project('test', [web], None)
  237. assert not project.uses_default_network()
  238. def test_uses_default_network_host(self):
  239. web = Service('web', project='test', image="alpine", net=Net('host'))
  240. project = Project('test', [web], None)
  241. assert not project.uses_default_network()
  242. def test_uses_default_network_container(self):
  243. container = mock.Mock(id='test')
  244. web = Service(
  245. 'web',
  246. project='test',
  247. image="alpine",
  248. net=ContainerNet(container))
  249. project = Project('test', [web], None)
  250. assert not project.uses_default_network()
  251. def test_container_without_name(self):
  252. self.mock_client.containers.return_value = [
  253. {'Image': 'busybox:latest', 'Id': '1', 'Name': '1'},
  254. {'Image': 'busybox:latest', 'Id': '2', 'Name': None},
  255. {'Image': 'busybox:latest', 'Id': '3'},
  256. ]
  257. self.mock_client.inspect_container.return_value = {
  258. 'Id': '1',
  259. 'Config': {
  260. 'Labels': {
  261. LABEL_SERVICE: 'web',
  262. },
  263. },
  264. }
  265. project = Project.from_config(
  266. 'test',
  267. Config(None, [{
  268. 'name': 'web',
  269. 'image': 'busybox:latest',
  270. }], None),
  271. self.mock_client,
  272. )
  273. self.assertEqual([c.id for c in project.containers()], ['1'])