project_test.py 10 KB

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