test_submission.py 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886
  1. # Copyright 2021-2024 Avaiga Private Limited
  2. #
  3. # Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
  4. # the License. You may obtain a copy of the License at
  5. #
  6. # http://www.apache.org/licenses/LICENSE-2.0
  7. #
  8. # Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
  9. # an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
  10. # specific language governing permissions and limitations under the License.
  11. from datetime import datetime
  12. import pytest
  13. from taipy.core import TaskId
  14. from taipy.core.job._job_manager_factory import _JobManagerFactory
  15. from taipy.core.job.job import Job
  16. from taipy.core.job.status import Status
  17. from taipy.core.submission._submission_manager_factory import _SubmissionManagerFactory
  18. from taipy.core.submission.submission import Submission
  19. from taipy.core.submission.submission_status import SubmissionStatus
  20. from taipy.core.task._task_manager_factory import _TaskManagerFactory
  21. from taipy.core.task.task import Task
  22. def test_create_submission(scenario, job, current_datetime):
  23. submission_1 = Submission(scenario.id, scenario._ID_PREFIX, scenario.config_id)
  24. assert submission_1.id is not None
  25. assert submission_1.entity_id == scenario.id
  26. assert submission_1.entity_type == scenario._ID_PREFIX
  27. assert submission_1.entity_config_id == scenario.config_id
  28. assert submission_1.jobs == []
  29. assert isinstance(submission_1.creation_date, datetime)
  30. assert submission_1._submission_status == SubmissionStatus.SUBMITTED
  31. assert submission_1._version is not None
  32. submission_2 = Submission(
  33. scenario.id,
  34. scenario._ID_PREFIX,
  35. scenario.config_id,
  36. "submission_id",
  37. [job],
  38. {"debug": True, "log": "log_file", "retry_note": 5},
  39. current_datetime,
  40. SubmissionStatus.COMPLETED,
  41. "version_id",
  42. )
  43. assert submission_2.id == "submission_id"
  44. assert submission_2.entity_id == scenario.id
  45. assert submission_2.entity_type == scenario._ID_PREFIX
  46. assert submission_2.entity_config_id == scenario.config_id
  47. assert submission_2._jobs == [job]
  48. assert submission_2._properties == {"debug": True, "log": "log_file", "retry_note": 5}
  49. assert submission_2.creation_date == current_datetime
  50. assert submission_2._submission_status == SubmissionStatus.COMPLETED
  51. assert submission_2._version == "version_id"
  52. class MockJob:
  53. def __init__(self, id: str, status):
  54. self.status = status
  55. self.id = id
  56. def is_failed(self):
  57. return self.status == Status.FAILED
  58. def is_canceled(self):
  59. return self.status == Status.CANCELED
  60. def is_blocked(self):
  61. return self.status == Status.BLOCKED
  62. def is_pending(self):
  63. return self.status == Status.PENDING
  64. def is_running(self):
  65. return self.status == Status.RUNNING
  66. def is_completed(self):
  67. return self.status == Status.COMPLETED
  68. def is_skipped(self):
  69. return self.status == Status.SKIPPED
  70. def is_abandoned(self):
  71. return self.status == Status.ABANDONED
  72. def is_submitted(self):
  73. return self.status == Status.SUBMITTED
  74. def __test_update_submission_status(job_ids, expected_submission_status):
  75. jobs = {
  76. "job0_submitted": MockJob("job0_submitted", Status.SUBMITTED),
  77. "job1_failed": MockJob("job1_failed", Status.FAILED),
  78. "job2_canceled": MockJob("job2_canceled", Status.CANCELED),
  79. "job3_blocked": MockJob("job3_blocked", Status.BLOCKED),
  80. "job4_pending": MockJob("job4_pending", Status.PENDING),
  81. "job5_running": MockJob("job5_running", Status.RUNNING),
  82. "job6_completed": MockJob("job6_completed", Status.COMPLETED),
  83. "job7_skipped": MockJob("job7_skipped", Status.SKIPPED),
  84. "job8_abandoned": MockJob("job8_abandoned", Status.ABANDONED),
  85. }
  86. submission = Submission("submission_id", "ENTITY_TYPE", "entity_config_id")
  87. submission.jobs = [jobs[job_id] for job_id in job_ids]
  88. for job_id in job_ids:
  89. job = jobs[job_id]
  90. submission._update_submission_status(job)
  91. assert submission.submission_status == expected_submission_status
  92. @pytest.mark.parametrize(
  93. "job_ids, expected_submission_status",
  94. [
  95. (["job1_failed"], SubmissionStatus.FAILED),
  96. (["job2_canceled"], SubmissionStatus.CANCELED),
  97. (["job3_blocked"], SubmissionStatus.BLOCKED),
  98. (["job4_pending"], SubmissionStatus.PENDING),
  99. (["job5_running"], SubmissionStatus.RUNNING),
  100. (["job6_completed"], SubmissionStatus.COMPLETED),
  101. (["job7_skipped"], SubmissionStatus.COMPLETED),
  102. (["job8_abandoned"], SubmissionStatus.UNDEFINED),
  103. ],
  104. )
  105. def test_update_single_submission_status(job_ids, expected_submission_status):
  106. __test_update_submission_status(job_ids, expected_submission_status)
  107. @pytest.mark.parametrize(
  108. "job_ids, expected_submission_status",
  109. [
  110. (["job1_failed", "job1_failed"], SubmissionStatus.FAILED),
  111. (["job1_failed", "job2_canceled"], SubmissionStatus.FAILED),
  112. (["job1_failed", "job3_blocked"], SubmissionStatus.FAILED),
  113. (["job1_failed", "job4_pending"], SubmissionStatus.FAILED),
  114. (["job1_failed", "job5_running"], SubmissionStatus.FAILED),
  115. (["job1_failed", "job6_completed"], SubmissionStatus.FAILED),
  116. (["job1_failed", "job7_skipped"], SubmissionStatus.FAILED),
  117. (["job1_failed", "job8_abandoned"], SubmissionStatus.FAILED),
  118. (["job2_canceled", "job1_failed"], SubmissionStatus.FAILED),
  119. (["job3_blocked", "job1_failed"], SubmissionStatus.FAILED),
  120. (["job4_pending", "job1_failed"], SubmissionStatus.FAILED),
  121. (["job5_running", "job1_failed"], SubmissionStatus.FAILED),
  122. (["job6_completed", "job1_failed"], SubmissionStatus.FAILED),
  123. (["job7_skipped", "job1_failed"], SubmissionStatus.FAILED),
  124. (["job8_abandoned", "job1_failed"], SubmissionStatus.FAILED),
  125. ],
  126. )
  127. def test_update_submission_status_with_one_failed_job_in_jobs(job_ids, expected_submission_status):
  128. __test_update_submission_status(job_ids, expected_submission_status)
  129. @pytest.mark.parametrize(
  130. "job_ids, expected_submission_status",
  131. [
  132. (["job2_canceled", "job2_canceled"], SubmissionStatus.CANCELED),
  133. (["job2_canceled", "job3_blocked"], SubmissionStatus.CANCELED),
  134. (["job2_canceled", "job4_pending"], SubmissionStatus.CANCELED),
  135. (["job2_canceled", "job5_running"], SubmissionStatus.CANCELED),
  136. (["job2_canceled", "job6_completed"], SubmissionStatus.CANCELED),
  137. (["job2_canceled", "job7_skipped"], SubmissionStatus.CANCELED),
  138. (["job2_canceled", "job8_abandoned"], SubmissionStatus.CANCELED),
  139. (["job3_blocked", "job2_canceled"], SubmissionStatus.CANCELED),
  140. (["job4_pending", "job2_canceled"], SubmissionStatus.CANCELED),
  141. (["job5_running", "job2_canceled"], SubmissionStatus.CANCELED),
  142. (["job6_completed", "job2_canceled"], SubmissionStatus.CANCELED),
  143. (["job7_skipped", "job2_canceled"], SubmissionStatus.CANCELED),
  144. (["job8_abandoned", "job2_canceled"], SubmissionStatus.CANCELED),
  145. ],
  146. )
  147. def test_update_submission_status_with_one_canceled_job_in_jobs(job_ids, expected_submission_status):
  148. __test_update_submission_status(job_ids, expected_submission_status)
  149. @pytest.mark.parametrize(
  150. "job_ids, expected_submission_status",
  151. [
  152. (["job4_pending", "job3_blocked"], SubmissionStatus.PENDING),
  153. (["job4_pending", "job4_pending"], SubmissionStatus.PENDING),
  154. (["job4_pending", "job6_completed"], SubmissionStatus.PENDING),
  155. (["job4_pending", "job7_skipped"], SubmissionStatus.PENDING),
  156. (["job3_blocked", "job4_pending"], SubmissionStatus.PENDING),
  157. (["job6_completed", "job4_pending"], SubmissionStatus.PENDING),
  158. (["job7_skipped", "job4_pending"], SubmissionStatus.PENDING),
  159. ],
  160. )
  161. def test_update_submission_status_with_no_failed_or_cancel_one_pending_in_jobs(job_ids, expected_submission_status):
  162. __test_update_submission_status(job_ids, expected_submission_status)
  163. @pytest.mark.parametrize(
  164. "job_ids, expected_submission_status",
  165. [
  166. (["job5_running", "job3_blocked"], SubmissionStatus.RUNNING),
  167. (["job5_running", "job4_pending"], SubmissionStatus.RUNNING),
  168. (["job5_running", "job5_running"], SubmissionStatus.RUNNING),
  169. (["job5_running", "job6_completed"], SubmissionStatus.RUNNING),
  170. (["job5_running", "job7_skipped"], SubmissionStatus.RUNNING),
  171. (["job3_blocked", "job5_running"], SubmissionStatus.RUNNING),
  172. (["job4_pending", "job5_running"], SubmissionStatus.RUNNING),
  173. (["job6_completed", "job5_running"], SubmissionStatus.RUNNING),
  174. (["job7_skipped", "job5_running"], SubmissionStatus.RUNNING),
  175. ],
  176. )
  177. def test_update_submission_status_with_no_failed_cancel_nor_pending_one_running_in_jobs(
  178. job_ids, expected_submission_status
  179. ):
  180. __test_update_submission_status(job_ids, expected_submission_status)
  181. @pytest.mark.parametrize(
  182. "job_ids, expected_submission_status",
  183. [
  184. (["job3_blocked", "job3_blocked"], SubmissionStatus.BLOCKED),
  185. (["job3_blocked", "job6_completed"], SubmissionStatus.BLOCKED),
  186. (["job3_blocked", "job7_skipped"], SubmissionStatus.BLOCKED),
  187. (["job6_completed", "job3_blocked"], SubmissionStatus.BLOCKED),
  188. (["job7_skipped", "job3_blocked"], SubmissionStatus.BLOCKED),
  189. ],
  190. )
  191. def test_update_submission_status_with_no_failed_cancel_pending_nor_running_one_blocked_in_jobs(
  192. job_ids, expected_submission_status
  193. ):
  194. __test_update_submission_status(job_ids, expected_submission_status)
  195. @pytest.mark.parametrize(
  196. "job_ids, expected_submission_status",
  197. [
  198. (["job6_completed", "job6_completed"], SubmissionStatus.COMPLETED),
  199. (["job6_completed", "job7_skipped"], SubmissionStatus.COMPLETED),
  200. (["job7_skipped", "job6_completed"], SubmissionStatus.COMPLETED),
  201. (["job7_skipped", "job7_skipped"], SubmissionStatus.COMPLETED),
  202. ],
  203. )
  204. def test_update_submission_status_with_only_completed_or_skipped_in_jobs(job_ids, expected_submission_status):
  205. __test_update_submission_status(job_ids, expected_submission_status)
  206. @pytest.mark.parametrize(
  207. "job_ids, expected_submission_status",
  208. [
  209. (["job3_blocked", "job8_abandoned"], SubmissionStatus.UNDEFINED),
  210. (["job4_pending", "job8_abandoned"], SubmissionStatus.UNDEFINED),
  211. (["job5_running", "job8_abandoned"], SubmissionStatus.UNDEFINED),
  212. (["job6_completed", "job8_abandoned"], SubmissionStatus.UNDEFINED),
  213. (["job7_skipped", "job8_abandoned"], SubmissionStatus.UNDEFINED),
  214. (["job8_abandoned", "job8_abandoned"], SubmissionStatus.UNDEFINED),
  215. (["job8_abandoned", "job3_blocked"], SubmissionStatus.UNDEFINED),
  216. (["job8_abandoned", "job4_pending"], SubmissionStatus.UNDEFINED),
  217. (["job8_abandoned", "job5_running"], SubmissionStatus.UNDEFINED),
  218. (["job8_abandoned", "job6_completed"], SubmissionStatus.UNDEFINED),
  219. (["job8_abandoned", "job7_skipped"], SubmissionStatus.UNDEFINED),
  220. ],
  221. )
  222. def test_update_submission_status_with_wrong_case_abandoned_without_cancel_or_failed_in_jobs(
  223. job_ids, expected_submission_status
  224. ):
  225. __test_update_submission_status(job_ids, expected_submission_status)
  226. def test_auto_set_and_reload():
  227. task = Task(config_id="name_1", properties={}, function=print, id=TaskId("task_1"))
  228. submission_1 = Submission(task.id, task._ID_PREFIX, task.config_id, properties={})
  229. job_1 = Job("job_1", task, submission_1.id, submission_1.entity_id)
  230. job_2 = Job("job_2", task, submission_1.id, submission_1.entity_id)
  231. _TaskManagerFactory._build_manager()._set(task)
  232. _SubmissionManagerFactory._build_manager()._set(submission_1)
  233. _JobManagerFactory._build_manager()._set(job_1)
  234. _JobManagerFactory._build_manager()._set(job_2)
  235. submission_2 = _SubmissionManagerFactory._build_manager()._get(submission_1)
  236. assert submission_1.id == submission_2.id
  237. assert submission_1.entity_id == submission_2.entity_id
  238. assert submission_1.creation_date == submission_2.creation_date
  239. assert submission_1.submission_status == submission_2.submission_status
  240. # auto set & reload on jobs attribute
  241. assert submission_1.jobs == []
  242. assert submission_2.jobs == []
  243. submission_1.jobs = [job_1]
  244. assert submission_1.jobs == [job_1]
  245. assert submission_2.jobs == [job_1]
  246. submission_2.jobs = [job_2]
  247. assert submission_1.jobs == [job_2]
  248. assert submission_2.jobs == [job_2]
  249. submission_1.jobs = [job_1, job_2]
  250. assert submission_1.jobs == [job_1, job_2]
  251. assert submission_2.jobs == [job_1, job_2]
  252. submission_2.jobs = [job_2, job_1]
  253. assert submission_1.jobs == [job_2, job_1]
  254. assert submission_2.jobs == [job_2, job_1]
  255. # auto set & reload on is_canceled attribute
  256. assert not submission_1.is_canceled
  257. assert not submission_2.is_canceled
  258. submission_1.is_canceled = True
  259. assert submission_1.is_canceled
  260. assert submission_2.is_canceled
  261. submission_2.is_canceled = False
  262. assert not submission_1.is_canceled
  263. assert not submission_2.is_canceled
  264. # auto set & reload on is_completed attribute
  265. assert not submission_1.is_completed
  266. assert not submission_2.is_completed
  267. submission_1.is_completed = True
  268. assert submission_1.is_completed
  269. assert submission_2.is_completed
  270. submission_2.is_completed = False
  271. assert not submission_1.is_completed
  272. assert not submission_2.is_completed
  273. # auto set & reload on is_abandoned attribute
  274. assert not submission_1.is_abandoned
  275. assert not submission_2.is_abandoned
  276. submission_1.is_abandoned = True
  277. assert submission_1.is_abandoned
  278. assert submission_2.is_abandoned
  279. submission_2.is_abandoned = False
  280. assert not submission_1.is_abandoned
  281. assert not submission_2.is_abandoned
  282. # auto set & reload on submission_status attribute
  283. assert submission_1.submission_status == SubmissionStatus.SUBMITTED
  284. assert submission_2.submission_status == SubmissionStatus.SUBMITTED
  285. submission_1.submission_status = SubmissionStatus.BLOCKED
  286. assert submission_1.submission_status == SubmissionStatus.BLOCKED
  287. assert submission_2.submission_status == SubmissionStatus.BLOCKED
  288. submission_2.submission_status = SubmissionStatus.COMPLETED
  289. assert submission_1.submission_status == SubmissionStatus.COMPLETED
  290. assert submission_2.submission_status == SubmissionStatus.COMPLETED
  291. with submission_1 as submission:
  292. assert submission.jobs == [job_2, job_1]
  293. assert submission.submission_status == SubmissionStatus.COMPLETED
  294. submission.jobs = [job_1]
  295. submission.submission_status = SubmissionStatus.PENDING
  296. assert submission.jobs == [job_2, job_1]
  297. assert submission.submission_status == SubmissionStatus.COMPLETED
  298. assert submission_1.jobs == [job_1]
  299. assert submission_1.submission_status == SubmissionStatus.PENDING
  300. assert submission_2.jobs == [job_1]
  301. assert submission_2.submission_status == SubmissionStatus.PENDING
  302. def test_auto_set_and_reload_properties():
  303. task = Task(config_id="name_1", properties={}, function=print, id=TaskId("task_1"))
  304. submission_1 = Submission(task.id, task._ID_PREFIX, task.config_id, properties={})
  305. _TaskManagerFactory._build_manager()._set(task)
  306. _SubmissionManagerFactory._build_manager()._set(submission_1)
  307. submission_2 = _SubmissionManagerFactory._build_manager()._get(submission_1)
  308. # auto set & reload on properties attribute
  309. assert submission_1.properties == {}
  310. assert submission_2.properties == {}
  311. submission_1._properties["qux"] = 4
  312. assert submission_1.properties["qux"] == 4
  313. assert submission_2.properties["qux"] == 4
  314. assert submission_1.properties == {"qux": 4}
  315. assert submission_2.properties == {"qux": 4}
  316. submission_2._properties["qux"] = 5
  317. assert submission_1.properties["qux"] == 5
  318. assert submission_2.properties["qux"] == 5
  319. submission_1.properties["temp_key_1"] = "temp_value_1"
  320. submission_1.properties["temp_key_2"] = "temp_value_2"
  321. assert submission_1.properties == {"qux": 5, "temp_key_1": "temp_value_1", "temp_key_2": "temp_value_2"}
  322. assert submission_2.properties == {"qux": 5, "temp_key_1": "temp_value_1", "temp_key_2": "temp_value_2"}
  323. submission_1.properties.pop("temp_key_1")
  324. assert "temp_key_1" not in submission_1.properties.keys()
  325. assert "temp_key_1" not in submission_1.properties.keys()
  326. assert submission_1.properties == {"qux": 5, "temp_key_2": "temp_value_2"}
  327. assert submission_2.properties == {"qux": 5, "temp_key_2": "temp_value_2"}
  328. submission_2.properties.pop("temp_key_2")
  329. assert submission_1.properties == {"qux": 5}
  330. assert submission_2.properties == {"qux": 5}
  331. assert "temp_key_2" not in submission_1.properties.keys()
  332. assert "temp_key_2" not in submission_2.properties.keys()
  333. submission_1.properties["temp_key_3"] = 0
  334. assert submission_1.properties == {"qux": 5, "temp_key_3": 0}
  335. assert submission_2.properties == {"qux": 5, "temp_key_3": 0}
  336. submission_1.properties.update({"temp_key_3": 1})
  337. assert submission_1.properties == {"qux": 5, "temp_key_3": 1}
  338. assert submission_2.properties == {"qux": 5, "temp_key_3": 1}
  339. submission_1.properties.update(dict())
  340. assert submission_1.properties == {"qux": 5, "temp_key_3": 1}
  341. assert submission_2.properties == {"qux": 5, "temp_key_3": 1}
  342. submission_1.properties["temp_key_4"] = 0
  343. submission_1.properties["temp_key_5"] = 0
  344. with submission_1 as submission:
  345. assert submission.properties["qux"] == 5
  346. assert submission.properties["temp_key_3"] == 1
  347. assert submission.properties["temp_key_4"] == 0
  348. assert submission.properties["temp_key_5"] == 0
  349. submission.properties["qux"] = 9
  350. submission.properties.pop("temp_key_3")
  351. submission.properties.pop("temp_key_4")
  352. submission.properties.update({"temp_key_4": 1})
  353. submission.properties.update({"temp_key_5": 2})
  354. submission.properties.pop("temp_key_5")
  355. submission.properties.update(dict())
  356. assert submission.properties["qux"] == 5
  357. assert submission.properties["temp_key_3"] == 1
  358. assert submission.properties["temp_key_4"] == 0
  359. assert submission.properties["temp_key_5"] == 0
  360. assert submission_1.properties["qux"] == 9
  361. assert "temp_key_3" not in submission_1.properties.keys()
  362. assert submission_1.properties["temp_key_4"] == 1
  363. assert "temp_key_5" not in submission_1.properties.keys()
  364. @pytest.mark.parametrize(
  365. "job_statuses, expected_submission_statuses",
  366. [
  367. (
  368. [Status.SUBMITTED, Status.PENDING, Status.RUNNING, Status.COMPLETED],
  369. [SubmissionStatus.PENDING, SubmissionStatus.PENDING, SubmissionStatus.RUNNING, SubmissionStatus.COMPLETED],
  370. ),
  371. (
  372. [Status.SUBMITTED, Status.PENDING, Status.RUNNING, Status.SKIPPED],
  373. [SubmissionStatus.PENDING, SubmissionStatus.PENDING, SubmissionStatus.RUNNING, SubmissionStatus.COMPLETED],
  374. ),
  375. (
  376. [Status.SUBMITTED, Status.PENDING, Status.RUNNING, Status.FAILED],
  377. [SubmissionStatus.PENDING, SubmissionStatus.PENDING, SubmissionStatus.RUNNING, SubmissionStatus.FAILED],
  378. ),
  379. (
  380. [Status.SUBMITTED, Status.PENDING, Status.CANCELED],
  381. [SubmissionStatus.PENDING, SubmissionStatus.PENDING, SubmissionStatus.CANCELED],
  382. ),
  383. (
  384. [Status.SUBMITTED, Status.PENDING, Status.RUNNING, Status.CANCELED],
  385. [SubmissionStatus.PENDING, SubmissionStatus.PENDING, SubmissionStatus.RUNNING, SubmissionStatus.CANCELED],
  386. ),
  387. ([Status.SUBMITTED, Status.BLOCKED], [SubmissionStatus.PENDING, SubmissionStatus.BLOCKED]),
  388. ([Status.SUBMITTED, Status.SKIPPED], [SubmissionStatus.PENDING, SubmissionStatus.COMPLETED]),
  389. ],
  390. )
  391. def test_update_submission_status_with_single_job_completed(job_statuses, expected_submission_statuses):
  392. job = MockJob("job_id", Status.SUBMITTED)
  393. submission = Submission("submission_id", "ENTITY_TYPE", "entity_config_id")
  394. _SubmissionManagerFactory._build_manager()._set(submission)
  395. assert submission.submission_status == SubmissionStatus.SUBMITTED
  396. for job_status, submission_status in zip(job_statuses, expected_submission_statuses):
  397. job.status = job_status
  398. submission._update_submission_status(job)
  399. assert submission.submission_status == submission_status
  400. def __test_update_submission_status_with_two_jobs(job_ids, job_statuses, expected_submission_statuses):
  401. jobs = {job_id: MockJob(job_id, Status.SUBMITTED) for job_id in job_ids}
  402. submission = Submission("submission_id", "ENTITY_TYPE", "entity_config_id")
  403. _SubmissionManagerFactory._build_manager()._set(submission)
  404. assert submission.submission_status == SubmissionStatus.SUBMITTED
  405. for (job_id, job_status), submission_status in zip(job_statuses, expected_submission_statuses):
  406. job = jobs[job_id]
  407. job.status = job_status
  408. submission._update_submission_status(job)
  409. assert submission.submission_status == submission_status
  410. @pytest.mark.parametrize(
  411. "job_ids, job_statuses, expected_submission_statuses",
  412. [
  413. (
  414. ["job_1", "job_2"],
  415. [
  416. ("job_1", Status.SUBMITTED),
  417. ("job_2", Status.SUBMITTED),
  418. ("job_1", Status.PENDING),
  419. ("job_2", Status.PENDING),
  420. ("job_1", Status.RUNNING),
  421. ("job_2", Status.RUNNING),
  422. ("job_1", Status.COMPLETED),
  423. ("job_2", Status.COMPLETED),
  424. ],
  425. [
  426. SubmissionStatus.PENDING,
  427. SubmissionStatus.PENDING,
  428. SubmissionStatus.PENDING,
  429. SubmissionStatus.PENDING,
  430. SubmissionStatus.RUNNING,
  431. SubmissionStatus.RUNNING,
  432. SubmissionStatus.RUNNING,
  433. SubmissionStatus.COMPLETED,
  434. ],
  435. ),
  436. (
  437. ["job_1", "job_2"],
  438. [
  439. ("job_1", Status.SUBMITTED),
  440. ("job_2", Status.SUBMITTED),
  441. ("job_1", Status.PENDING),
  442. ("job_1", Status.RUNNING),
  443. ("job_2", Status.PENDING),
  444. ("job_2", Status.RUNNING),
  445. ("job_1", Status.COMPLETED),
  446. ("job_2", Status.COMPLETED),
  447. ],
  448. [
  449. SubmissionStatus.PENDING,
  450. SubmissionStatus.PENDING,
  451. SubmissionStatus.PENDING,
  452. SubmissionStatus.RUNNING,
  453. SubmissionStatus.RUNNING,
  454. SubmissionStatus.RUNNING,
  455. SubmissionStatus.RUNNING,
  456. SubmissionStatus.COMPLETED,
  457. ],
  458. ),
  459. (
  460. ["job_1", "job_2"],
  461. [
  462. ("job_1", Status.SUBMITTED),
  463. ("job_2", Status.SUBMITTED),
  464. ("job_1", Status.BLOCKED),
  465. ("job_2", Status.PENDING),
  466. ("job_2", Status.RUNNING),
  467. ("job_2", Status.COMPLETED),
  468. ("job_1", Status.PENDING),
  469. ("job_1", Status.RUNNING),
  470. ("job_1", Status.COMPLETED),
  471. ],
  472. [
  473. SubmissionStatus.PENDING,
  474. SubmissionStatus.PENDING,
  475. SubmissionStatus.PENDING,
  476. SubmissionStatus.PENDING,
  477. SubmissionStatus.RUNNING,
  478. SubmissionStatus.BLOCKED,
  479. SubmissionStatus.PENDING,
  480. SubmissionStatus.RUNNING,
  481. SubmissionStatus.COMPLETED,
  482. ],
  483. ),
  484. ],
  485. )
  486. def test_update_submission_status_with_two_jobs_completed(job_ids, job_statuses, expected_submission_statuses):
  487. __test_update_submission_status_with_two_jobs(job_ids, job_statuses, expected_submission_statuses)
  488. @pytest.mark.parametrize(
  489. "job_ids, job_statuses, expected_submission_statuses",
  490. [
  491. (
  492. ["job_1", "job_2"],
  493. [
  494. ("job_1", Status.SUBMITTED),
  495. ("job_2", Status.SUBMITTED),
  496. ("job_1", Status.PENDING),
  497. ("job_2", Status.PENDING),
  498. ("job_1", Status.RUNNING),
  499. ("job_2", Status.SKIPPED),
  500. ("job_1", Status.COMPLETED),
  501. ],
  502. [
  503. SubmissionStatus.PENDING,
  504. SubmissionStatus.PENDING,
  505. SubmissionStatus.PENDING,
  506. SubmissionStatus.PENDING,
  507. SubmissionStatus.RUNNING,
  508. SubmissionStatus.RUNNING,
  509. SubmissionStatus.COMPLETED,
  510. ],
  511. ),
  512. (
  513. ["job_1", "job_2"],
  514. [
  515. ("job_1", Status.SUBMITTED),
  516. ("job_2", Status.SUBMITTED),
  517. ("job_1", Status.PENDING),
  518. ("job_1", Status.RUNNING),
  519. ("job_2", Status.PENDING),
  520. ("job_2", Status.SKIPPED),
  521. ("job_1", Status.COMPLETED),
  522. ],
  523. [
  524. SubmissionStatus.PENDING,
  525. SubmissionStatus.PENDING,
  526. SubmissionStatus.PENDING,
  527. SubmissionStatus.RUNNING,
  528. SubmissionStatus.RUNNING,
  529. SubmissionStatus.RUNNING,
  530. SubmissionStatus.COMPLETED,
  531. ],
  532. ),
  533. (
  534. ["job_1", "job_2"],
  535. [
  536. ("job_1", Status.SUBMITTED),
  537. ("job_2", Status.SUBMITTED),
  538. ("job_1", Status.BLOCKED),
  539. ("job_2", Status.PENDING),
  540. ("job_2", Status.RUNNING),
  541. ("job_2", Status.COMPLETED),
  542. ("job_1", Status.PENDING),
  543. ("job_1", Status.SKIPPED),
  544. ],
  545. [
  546. SubmissionStatus.PENDING,
  547. SubmissionStatus.PENDING,
  548. SubmissionStatus.PENDING,
  549. SubmissionStatus.PENDING,
  550. SubmissionStatus.RUNNING,
  551. SubmissionStatus.BLOCKED,
  552. SubmissionStatus.PENDING,
  553. SubmissionStatus.COMPLETED,
  554. ],
  555. ),
  556. (
  557. ["job_1", "job_2"],
  558. [
  559. ("job_1", Status.SUBMITTED),
  560. ("job_2", Status.SUBMITTED),
  561. ("job_1", Status.PENDING),
  562. ("job_2", Status.PENDING),
  563. ("job_1", Status.SKIPPED),
  564. ("job_2", Status.SKIPPED),
  565. ],
  566. [
  567. SubmissionStatus.PENDING,
  568. SubmissionStatus.PENDING,
  569. SubmissionStatus.PENDING,
  570. SubmissionStatus.PENDING,
  571. SubmissionStatus.PENDING,
  572. SubmissionStatus.COMPLETED,
  573. ],
  574. ),
  575. (
  576. ["job_1", "job_2"],
  577. [
  578. ("job_1", Status.SUBMITTED),
  579. ("job_2", Status.SUBMITTED),
  580. ("job_1", Status.PENDING),
  581. ("job_1", Status.SKIPPED),
  582. ("job_2", Status.PENDING),
  583. ("job_2", Status.SKIPPED),
  584. ],
  585. [
  586. SubmissionStatus.PENDING,
  587. SubmissionStatus.PENDING,
  588. SubmissionStatus.PENDING,
  589. SubmissionStatus.PENDING,
  590. SubmissionStatus.PENDING,
  591. SubmissionStatus.COMPLETED,
  592. ],
  593. ),
  594. (
  595. ["job_1", "job_2"],
  596. [
  597. ("job_1", Status.SUBMITTED),
  598. ("job_2", Status.SUBMITTED),
  599. ("job_1", Status.BLOCKED),
  600. ("job_2", Status.PENDING),
  601. ("job_2", Status.SKIPPED),
  602. ("job_1", Status.PENDING),
  603. ("job_1", Status.SKIPPED),
  604. ],
  605. [
  606. SubmissionStatus.PENDING,
  607. SubmissionStatus.PENDING,
  608. SubmissionStatus.PENDING,
  609. SubmissionStatus.PENDING,
  610. SubmissionStatus.BLOCKED,
  611. SubmissionStatus.PENDING,
  612. SubmissionStatus.COMPLETED,
  613. ],
  614. ),
  615. ],
  616. )
  617. def test_update_submission_status_with_two_jobs_skipped(job_ids, job_statuses, expected_submission_statuses):
  618. __test_update_submission_status_with_two_jobs(job_ids, job_statuses, expected_submission_statuses)
  619. @pytest.mark.parametrize(
  620. "job_ids, job_statuses, expected_submission_statuses",
  621. [
  622. (
  623. ["job_1", "job_2"],
  624. [
  625. ("job_1", Status.SUBMITTED),
  626. ("job_2", Status.SUBMITTED),
  627. ("job_1", Status.PENDING),
  628. ("job_2", Status.PENDING),
  629. ("job_1", Status.RUNNING),
  630. ("job_2", Status.RUNNING),
  631. ("job_1", Status.FAILED),
  632. ("job_2", Status.COMPLETED),
  633. ],
  634. [
  635. SubmissionStatus.PENDING,
  636. SubmissionStatus.PENDING,
  637. SubmissionStatus.PENDING,
  638. SubmissionStatus.PENDING,
  639. SubmissionStatus.RUNNING,
  640. SubmissionStatus.RUNNING,
  641. SubmissionStatus.FAILED,
  642. SubmissionStatus.FAILED,
  643. ],
  644. ),
  645. (
  646. ["job_1", "job_2"],
  647. [
  648. ("job_1", Status.SUBMITTED),
  649. ("job_2", Status.SUBMITTED),
  650. ("job_1", Status.PENDING),
  651. ("job_1", Status.RUNNING),
  652. ("job_2", Status.PENDING),
  653. ("job_2", Status.RUNNING),
  654. ("job_1", Status.COMPLETED),
  655. ("job_2", Status.FAILED),
  656. ],
  657. [
  658. SubmissionStatus.PENDING,
  659. SubmissionStatus.PENDING,
  660. SubmissionStatus.PENDING,
  661. SubmissionStatus.RUNNING,
  662. SubmissionStatus.RUNNING,
  663. SubmissionStatus.RUNNING,
  664. SubmissionStatus.RUNNING,
  665. SubmissionStatus.FAILED,
  666. ],
  667. ),
  668. (
  669. ["job_1", "job_2"],
  670. [
  671. ("job_1", Status.SUBMITTED),
  672. ("job_2", Status.SUBMITTED),
  673. ("job_1", Status.BLOCKED),
  674. ("job_2", Status.PENDING),
  675. ("job_2", Status.RUNNING),
  676. ("job_2", Status.FAILED),
  677. ("job_1", Status.ABANDONED),
  678. ],
  679. [
  680. SubmissionStatus.PENDING,
  681. SubmissionStatus.PENDING,
  682. SubmissionStatus.PENDING,
  683. SubmissionStatus.PENDING,
  684. SubmissionStatus.RUNNING,
  685. SubmissionStatus.FAILED,
  686. SubmissionStatus.FAILED,
  687. ],
  688. ),
  689. ],
  690. )
  691. def test_update_submission_status_with_two_jobs_failed(job_ids, job_statuses, expected_submission_statuses):
  692. __test_update_submission_status_with_two_jobs(job_ids, job_statuses, expected_submission_statuses)
  693. @pytest.mark.parametrize(
  694. "job_ids, job_statuses, expected_submission_statuses",
  695. [
  696. (
  697. ["job_1", "job_2"],
  698. [
  699. ("job_1", Status.SUBMITTED),
  700. ("job_2", Status.SUBMITTED),
  701. ("job_1", Status.PENDING),
  702. ("job_2", Status.PENDING),
  703. ("job_1", Status.RUNNING),
  704. ("job_2", Status.RUNNING),
  705. ("job_1", Status.CANCELED),
  706. ("job_2", Status.COMPLETED),
  707. ],
  708. [
  709. SubmissionStatus.PENDING,
  710. SubmissionStatus.PENDING,
  711. SubmissionStatus.PENDING,
  712. SubmissionStatus.PENDING,
  713. SubmissionStatus.RUNNING,
  714. SubmissionStatus.RUNNING,
  715. SubmissionStatus.CANCELED,
  716. SubmissionStatus.CANCELED,
  717. ],
  718. ),
  719. (
  720. ["job_1", "job_2"],
  721. [
  722. ("job_1", Status.SUBMITTED),
  723. ("job_2", Status.SUBMITTED),
  724. ("job_1", Status.PENDING),
  725. ("job_1", Status.RUNNING),
  726. ("job_2", Status.PENDING),
  727. ("job_2", Status.RUNNING),
  728. ("job_1", Status.COMPLETED),
  729. ("job_2", Status.CANCELED),
  730. ],
  731. [
  732. SubmissionStatus.PENDING,
  733. SubmissionStatus.PENDING,
  734. SubmissionStatus.PENDING,
  735. SubmissionStatus.RUNNING,
  736. SubmissionStatus.RUNNING,
  737. SubmissionStatus.RUNNING,
  738. SubmissionStatus.RUNNING,
  739. SubmissionStatus.CANCELED,
  740. ],
  741. ),
  742. (
  743. ["job_1", "job_2"],
  744. [
  745. ("job_1", Status.SUBMITTED),
  746. ("job_2", Status.SUBMITTED),
  747. ("job_1", Status.BLOCKED),
  748. ("job_2", Status.PENDING),
  749. ("job_2", Status.RUNNING),
  750. ("job_2", Status.CANCELED),
  751. ("job_1", Status.ABANDONED),
  752. ],
  753. [
  754. SubmissionStatus.PENDING,
  755. SubmissionStatus.PENDING,
  756. SubmissionStatus.PENDING,
  757. SubmissionStatus.PENDING,
  758. SubmissionStatus.RUNNING,
  759. SubmissionStatus.CANCELED,
  760. SubmissionStatus.CANCELED,
  761. ],
  762. ),
  763. ],
  764. )
  765. def test_update_submission_status_with_two_jobs_canceled(job_ids, job_statuses, expected_submission_statuses):
  766. __test_update_submission_status_with_two_jobs(job_ids, job_statuses, expected_submission_statuses)
  767. def test_is_finished():
  768. submission_manager = _SubmissionManagerFactory._build_manager()
  769. submission = Submission("entity_id", "entity_type", "entity_config_id", "submission_id")
  770. submission_manager._set(submission)
  771. assert len(submission_manager._get_all()) == 1
  772. assert submission._submission_status == SubmissionStatus.SUBMITTED
  773. assert not submission.is_finished()
  774. submission.submission_status = SubmissionStatus.UNDEFINED
  775. assert submission.submission_status == SubmissionStatus.UNDEFINED
  776. assert not submission.is_finished()
  777. submission.submission_status = SubmissionStatus.CANCELED
  778. assert submission.submission_status == SubmissionStatus.CANCELED
  779. assert submission.is_finished()
  780. submission.submission_status = SubmissionStatus.FAILED
  781. assert submission.submission_status == SubmissionStatus.FAILED
  782. assert submission.is_finished()
  783. submission.submission_status = SubmissionStatus.BLOCKED
  784. assert submission.submission_status == SubmissionStatus.BLOCKED
  785. assert not submission.is_finished()
  786. submission.submission_status = SubmissionStatus.RUNNING
  787. assert submission.submission_status == SubmissionStatus.RUNNING
  788. assert not submission.is_finished()
  789. submission.submission_status = SubmissionStatus.PENDING
  790. assert submission.submission_status == SubmissionStatus.PENDING
  791. assert not submission.is_finished()
  792. submission.submission_status = SubmissionStatus.COMPLETED
  793. assert submission.submission_status == SubmissionStatus.COMPLETED
  794. assert submission.is_finished()