test_container.py 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458
  1. import pytest
  2. from render import Render
  3. @pytest.fixture
  4. def mock_values():
  5. return {
  6. "images": {
  7. "test_image": {
  8. "repository": "nginx",
  9. "tag": "latest",
  10. }
  11. },
  12. }
  13. def test_empty_container_name(mock_values):
  14. render = Render(mock_values)
  15. with pytest.raises(Exception):
  16. render.add_container(" ", "test_image")
  17. def test_resolve_image(mock_values):
  18. render = Render(mock_values)
  19. c1 = render.add_container("test_container", "test_image")
  20. c1.healthcheck.disable()
  21. output = render.render()
  22. assert output["services"]["test_container"]["image"] == "nginx:latest"
  23. def test_missing_repo(mock_values):
  24. mock_values["images"]["test_image"]["repository"] = ""
  25. render = Render(mock_values)
  26. with pytest.raises(Exception):
  27. render.add_container("test_container", "test_image")
  28. def test_missing_tag(mock_values):
  29. mock_values["images"]["test_image"]["tag"] = ""
  30. render = Render(mock_values)
  31. with pytest.raises(Exception):
  32. render.add_container("test_container", "test_image")
  33. def test_non_existing_image(mock_values):
  34. render = Render(mock_values)
  35. with pytest.raises(Exception):
  36. render.add_container("test_container", "non_existing_image")
  37. def test_pull_policy(mock_values):
  38. render = Render(mock_values)
  39. c1 = render.add_container("test_container", "test_image")
  40. c1.set_pull_policy("always")
  41. c1.healthcheck.disable()
  42. output = render.render()
  43. assert output["services"]["test_container"]["pull_policy"] == "always"
  44. def test_invalid_pull_policy(mock_values):
  45. render = Render(mock_values)
  46. c1 = render.add_container("test_container", "test_image")
  47. with pytest.raises(Exception):
  48. c1.set_pull_policy("invalid_policy")
  49. def test_clear_caps(mock_values):
  50. render = Render(mock_values)
  51. c1 = render.add_container("test_container", "test_image")
  52. c1.add_caps(["NET_ADMIN"])
  53. c1.clear_caps()
  54. c1.healthcheck.disable()
  55. output = render.render()
  56. assert "cap_drop" not in output["services"]["test_container"]
  57. assert "cap_add" not in output["services"]["test_container"]
  58. def test_privileged(mock_values):
  59. render = Render(mock_values)
  60. c1 = render.add_container("test_container", "test_image")
  61. c1.set_privileged(True)
  62. c1.healthcheck.disable()
  63. output = render.render()
  64. assert output["services"]["test_container"]["privileged"] is True
  65. def test_tty(mock_values):
  66. render = Render(mock_values)
  67. c1 = render.add_container("test_container", "test_image")
  68. c1.set_tty(True)
  69. c1.healthcheck.disable()
  70. output = render.render()
  71. assert output["services"]["test_container"]["tty"] is True
  72. def test_init(mock_values):
  73. render = Render(mock_values)
  74. c1 = render.add_container("test_container", "test_image")
  75. c1.set_init(True)
  76. c1.healthcheck.disable()
  77. output = render.render()
  78. assert output["services"]["test_container"]["init"] is True
  79. def test_read_only(mock_values):
  80. render = Render(mock_values)
  81. c1 = render.add_container("test_container", "test_image")
  82. c1.set_read_only(True)
  83. c1.healthcheck.disable()
  84. output = render.render()
  85. assert output["services"]["test_container"]["read_only"] is True
  86. def test_stdin(mock_values):
  87. render = Render(mock_values)
  88. c1 = render.add_container("test_container", "test_image")
  89. c1.set_stdin(True)
  90. c1.healthcheck.disable()
  91. output = render.render()
  92. assert output["services"]["test_container"]["stdin_open"] is True
  93. def test_hostname(mock_values):
  94. render = Render(mock_values)
  95. c1 = render.add_container("test_container", "test_image")
  96. c1.set_hostname("test_hostname")
  97. c1.healthcheck.disable()
  98. output = render.render()
  99. assert output["services"]["test_container"]["hostname"] == "test_hostname"
  100. def test_grace_period(mock_values):
  101. render = Render(mock_values)
  102. c1 = render.add_container("test_container", "test_image")
  103. c1.set_grace_period(10)
  104. c1.healthcheck.disable()
  105. output = render.render()
  106. assert output["services"]["test_container"]["stop_grace_period"] == "10s"
  107. def test_user(mock_values):
  108. render = Render(mock_values)
  109. c1 = render.add_container("test_container", "test_image")
  110. c1.set_user(1000, 1000)
  111. c1.healthcheck.disable()
  112. output = render.render()
  113. assert output["services"]["test_container"]["user"] == "1000:1000"
  114. def test_invalid_user(mock_values):
  115. render = Render(mock_values)
  116. c1 = render.add_container("test_container", "test_image")
  117. c1.healthcheck.disable()
  118. with pytest.raises(Exception):
  119. c1.set_user(-100, 1000)
  120. def test_add_group(mock_values):
  121. render = Render(mock_values)
  122. c1 = render.add_container("test_container", "test_image")
  123. c1.healthcheck.disable()
  124. c1.add_group(1000)
  125. c1.add_group("video")
  126. output = render.render()
  127. assert output["services"]["test_container"]["group_add"] == [568, 1000, "video"]
  128. def test_add_duplicate_group(mock_values):
  129. render = Render(mock_values)
  130. c1 = render.add_container("test_container", "test_image")
  131. c1.healthcheck.disable()
  132. c1.add_group(1000)
  133. with pytest.raises(Exception):
  134. c1.add_group(1000)
  135. def test_add_group_as_string(mock_values):
  136. render = Render(mock_values)
  137. c1 = render.add_container("test_container", "test_image")
  138. c1.healthcheck.disable()
  139. with pytest.raises(Exception):
  140. c1.add_group("1000")
  141. def test_add_docker_socket(mock_values):
  142. render = Render(mock_values)
  143. c1 = render.add_container("test_container", "test_image")
  144. c1.healthcheck.disable()
  145. c1.add_docker_socket()
  146. output = render.render()
  147. assert output["services"]["test_container"]["group_add"] == [568, 999]
  148. assert output["services"]["test_container"]["volumes"] == [
  149. {
  150. "type": "bind",
  151. "source": "/var/run/docker.sock",
  152. "target": "/var/run/docker.sock",
  153. "read_only": True,
  154. "bind": {
  155. "propagation": "rprivate",
  156. "create_host_path": False,
  157. },
  158. }
  159. ]
  160. def test_snd_device(mock_values):
  161. render = Render(mock_values)
  162. c1 = render.add_container("test_container", "test_image")
  163. c1.healthcheck.disable()
  164. c1.add_snd_device()
  165. output = render.render()
  166. assert output["services"]["test_container"]["devices"] == ["/dev/snd:/dev/snd"]
  167. assert output["services"]["test_container"]["group_add"] == [29, 568]
  168. def test_shm_size(mock_values):
  169. render = Render(mock_values)
  170. c1 = render.add_container("test_container", "test_image")
  171. c1.healthcheck.disable()
  172. c1.set_shm_size_mb(10)
  173. output = render.render()
  174. assert output["services"]["test_container"]["shm_size"] == "10M"
  175. def test_valid_caps(mock_values):
  176. render = Render(mock_values)
  177. c1 = render.add_container("test_container", "test_image")
  178. c1.healthcheck.disable()
  179. c1.add_caps(["ALL", "NET_ADMIN"])
  180. output = render.render()
  181. assert output["services"]["test_container"]["cap_add"] == ["ALL", "NET_ADMIN"]
  182. assert output["services"]["test_container"]["cap_drop"] == ["ALL"]
  183. def test_add_duplicate_caps(mock_values):
  184. render = Render(mock_values)
  185. c1 = render.add_container("test_container", "test_image")
  186. c1.healthcheck.disable()
  187. with pytest.raises(Exception):
  188. c1.add_caps(["ALL", "NET_ADMIN", "NET_ADMIN"])
  189. def test_invalid_caps(mock_values):
  190. render = Render(mock_values)
  191. c1 = render.add_container("test_container", "test_image")
  192. c1.healthcheck.disable()
  193. with pytest.raises(Exception):
  194. c1.add_caps(["invalid_cap"])
  195. def test_network_mode(mock_values):
  196. render = Render(mock_values)
  197. c1 = render.add_container("test_container", "test_image")
  198. c1.healthcheck.disable()
  199. c1.set_network_mode("host")
  200. output = render.render()
  201. assert output["services"]["test_container"]["network_mode"] == "host"
  202. def test_auto_network_mode_with_host_network(mock_values):
  203. mock_values["network"] = {"host_network": True}
  204. render = Render(mock_values)
  205. c1 = render.add_container("test_container", "test_image")
  206. c1.healthcheck.disable()
  207. output = render.render()
  208. assert output["services"]["test_container"]["network_mode"] == "host"
  209. def test_network_mode_with_container(mock_values):
  210. render = Render(mock_values)
  211. c1 = render.add_container("test_container", "test_image")
  212. c1.healthcheck.disable()
  213. c1.set_network_mode("service:test_container")
  214. output = render.render()
  215. assert output["services"]["test_container"]["network_mode"] == "service:test_container"
  216. def test_network_mode_with_container_missing(mock_values):
  217. render = Render(mock_values)
  218. c1 = render.add_container("test_container", "test_image")
  219. c1.healthcheck.disable()
  220. with pytest.raises(Exception):
  221. c1.set_network_mode("service:missing_container")
  222. def test_invalid_network_mode(mock_values):
  223. render = Render(mock_values)
  224. c1 = render.add_container("test_container", "test_image")
  225. c1.healthcheck.disable()
  226. with pytest.raises(Exception):
  227. c1.set_network_mode("invalid_mode")
  228. def test_entrypoint(mock_values):
  229. render = Render(mock_values)
  230. c1 = render.add_container("test_container", "test_image")
  231. c1.set_entrypoint(["/bin/bash", "-c", "echo hello $MY_ENV"])
  232. c1.healthcheck.disable()
  233. output = render.render()
  234. assert output["services"]["test_container"]["entrypoint"] == ["/bin/bash", "-c", "echo hello $$MY_ENV"]
  235. def test_command(mock_values):
  236. render = Render(mock_values)
  237. c1 = render.add_container("test_container", "test_image")
  238. c1.set_command(["echo", "hello $MY_ENV"])
  239. c1.healthcheck.disable()
  240. output = render.render()
  241. assert output["services"]["test_container"]["command"] == ["echo", "hello $$MY_ENV"]
  242. def test_add_ports(mock_values):
  243. render = Render(mock_values)
  244. c1 = render.add_container("test_container", "test_image")
  245. c1.healthcheck.disable()
  246. c1.add_port({"port_number": 8081, "container_port": 8080, "bind_mode": "published"})
  247. c1.add_port({"port_number": 8082, "container_port": 8080, "bind_mode": "published", "protocol": "udp"})
  248. c1.add_port({"port_number": 8083, "container_port": 8080, "bind_mode": "exposed"})
  249. c1.add_port({"port_number": 8084, "container_port": 8080, "bind_mode": ""})
  250. c1.add_port(
  251. {"port_number": 9091, "container_port": 9091, "bind_mode": "published"},
  252. {"container_port": 9092, "protocol": "udp"},
  253. )
  254. output = render.render()
  255. assert output["services"]["test_container"]["ports"] == [
  256. {"published": 8081, "target": 8080, "protocol": "tcp", "mode": "ingress"},
  257. {"published": 8082, "target": 8080, "protocol": "udp", "mode": "ingress"},
  258. {"published": 9091, "target": 9092, "protocol": "udp", "mode": "ingress"},
  259. ]
  260. assert output["services"]["test_container"]["expose"] == ["8080/tcp"]
  261. def test_add_ports_with_invalid_host_ips(mock_values):
  262. render = Render(mock_values)
  263. c1 = render.add_container("test_container", "test_image")
  264. c1.healthcheck.disable()
  265. with pytest.raises(Exception):
  266. c1.add_port({"port_number": 8081, "container_port": 8080, "bind_mode": "published", "host_ips": "invalid"})
  267. def test_add_ports_with_empty_host_ips(mock_values):
  268. render = Render(mock_values)
  269. c1 = render.add_container("test_container", "test_image")
  270. c1.healthcheck.disable()
  271. c1.add_port({"port_number": 8081, "container_port": 8080, "bind_mode": "published", "host_ips": []})
  272. output = render.render()
  273. assert output["services"]["test_container"]["ports"] == [
  274. {"published": 8081, "target": 8080, "protocol": "tcp", "mode": "ingress"}
  275. ]
  276. def test_set_ipc_mode(mock_values):
  277. render = Render(mock_values)
  278. c1 = render.add_container("test_container", "test_image")
  279. c1.healthcheck.disable()
  280. c1.set_ipc_mode("host")
  281. output = render.render()
  282. assert output["services"]["test_container"]["ipc"] == "host"
  283. def test_set_ipc_empty_mode(mock_values):
  284. render = Render(mock_values)
  285. c1 = render.add_container("test_container", "test_image")
  286. c1.healthcheck.disable()
  287. c1.set_ipc_mode("")
  288. output = render.render()
  289. assert output["services"]["test_container"]["ipc"] == ""
  290. def test_set_ipc_mode_with_invalid_ipc_mode(mock_values):
  291. render = Render(mock_values)
  292. c1 = render.add_container("test_container", "test_image")
  293. c1.healthcheck.disable()
  294. with pytest.raises(Exception):
  295. c1.set_ipc_mode("invalid")
  296. def test_set_ipc_mode_with_container_ipc_mode(mock_values):
  297. render = Render(mock_values)
  298. c1 = render.add_container("test_container", "test_image")
  299. c1.healthcheck.disable()
  300. c2 = render.add_container("test_container2", "test_image")
  301. c2.healthcheck.disable()
  302. c1.set_ipc_mode("container:test_container2")
  303. output = render.render()
  304. assert output["services"]["test_container"]["ipc"] == "container:test_container2"
  305. def test_set_ipc_mode_with_container_ipc_mode_and_invalid_container(mock_values):
  306. render = Render(mock_values)
  307. c1 = render.add_container("test_container", "test_image")
  308. c1.healthcheck.disable()
  309. with pytest.raises(Exception):
  310. c1.set_ipc_mode("container:invalid")
  311. def test_set_pid_mode(mock_values):
  312. render = Render(mock_values)
  313. c1 = render.add_container("test_container", "test_image")
  314. c1.healthcheck.disable()
  315. c1.set_pid_mode("host")
  316. output = render.render()
  317. assert output["services"]["test_container"]["pid"] == "host"
  318. def test_set_pid_empty_mode(mock_values):
  319. render = Render(mock_values)
  320. c1 = render.add_container("test_container", "test_image")
  321. c1.healthcheck.disable()
  322. c1.set_pid_mode("")
  323. output = render.render()
  324. assert output["services"]["test_container"]["pid"] == ""
  325. def test_set_pid_mode_with_invalid_pid_mode(mock_values):
  326. render = Render(mock_values)
  327. c1 = render.add_container("test_container", "test_image")
  328. c1.healthcheck.disable()
  329. with pytest.raises(Exception):
  330. c1.set_pid_mode("invalid")
  331. def test_set_pid_mode_with_container_pid_mode(mock_values):
  332. render = Render(mock_values)
  333. c1 = render.add_container("test_container", "test_image")
  334. c1.healthcheck.disable()
  335. c2 = render.add_container("test_container2", "test_image")
  336. c2.healthcheck.disable()
  337. c1.set_pid_mode("container:test_container2")
  338. output = render.render()
  339. assert output["services"]["test_container"]["pid"] == "container:test_container2"
  340. def test_set_pid_mode_with_container_pid_mode_and_invalid_container(mock_values):
  341. render = Render(mock_values)
  342. c1 = render.add_container("test_container", "test_image")
  343. c1.healthcheck.disable()
  344. with pytest.raises(Exception):
  345. c1.set_pid_mode("container:invalid")
  346. def test_set_cgroup(mock_values):
  347. render = Render(mock_values)
  348. c1 = render.add_container("test_container", "test_image")
  349. c1.healthcheck.disable()
  350. c1.set_cgroup("host")
  351. output = render.render()
  352. assert output["services"]["test_container"]["cgroup"] == "host"
  353. def test_set_cgroup_invalid(mock_values):
  354. render = Render(mock_values)
  355. c1 = render.add_container("test_container", "test_image")
  356. c1.healthcheck.disable()
  357. with pytest.raises(Exception):
  358. c1.set_cgroup("invalid")