test_submission.py 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950
  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_job_sets():
  303. # pending_jobs, running_jobs, blocked_jobs have the same behavior
  304. # so we will only test 1 attribute (pending_jobs) as representative
  305. task = Task(config_id="name_1", properties={}, function=print, id=TaskId("task_1"))
  306. submission_1 = Submission(task.id, task._ID_PREFIX, task.config_id, properties={})
  307. _TaskManagerFactory._build_manager()._set(task)
  308. _SubmissionManagerFactory._build_manager()._set(submission_1)
  309. submission_2 = _SubmissionManagerFactory._build_manager()._get(submission_1)
  310. # auto set & reload on pending_jobs attribute
  311. assert len(submission_1.pending_jobs) == 0
  312. assert len(submission_1.pending_jobs) == 0
  313. submission_1.pending_jobs.add("job_id_1")
  314. assert submission_1.pending_jobs.data == set(["job_id_1"])
  315. assert submission_2.pending_jobs.data == set(["job_id_1"])
  316. assert len(submission_1.pending_jobs) == 1
  317. assert len(submission_1.pending_jobs) == 1
  318. submission_2.pending_jobs.add("job_id_2")
  319. assert submission_1.pending_jobs.data == set(["job_id_1", "job_id_2"])
  320. assert submission_2.pending_jobs.data == set(["job_id_1", "job_id_2"])
  321. submission_1.pending_jobs.add("job_id_tmp_1")
  322. submission_2.pending_jobs.add("job_id_tmp_2")
  323. assert submission_1.pending_jobs.data == set(["job_id_1", "job_id_2", "job_id_tmp_1", "job_id_tmp_2"])
  324. assert submission_2.pending_jobs.data == set(["job_id_1", "job_id_2", "job_id_tmp_1", "job_id_tmp_2"])
  325. submission_1.pending_jobs.remove("job_id_tmp_1")
  326. assert submission_1.pending_jobs.data == set(["job_id_1", "job_id_2", "job_id_tmp_2"])
  327. assert submission_2.pending_jobs.data == set(["job_id_1", "job_id_2", "job_id_tmp_2"])
  328. submission_2.pending_jobs.remove("job_id_tmp_2")
  329. assert submission_1.pending_jobs.data == set(["job_id_1", "job_id_2"])
  330. assert submission_2.pending_jobs.data == set(["job_id_1", "job_id_2"])
  331. submission_1.pending_jobs.add("job_id_tmp_1")
  332. submission_2.pending_jobs.add("job_id_tmp_2")
  333. assert submission_1.pending_jobs.data == set(["job_id_1", "job_id_2", "job_id_tmp_1", "job_id_tmp_2"])
  334. assert submission_2.pending_jobs.data == set(["job_id_1", "job_id_2", "job_id_tmp_1", "job_id_tmp_2"])
  335. submission_1.pending_jobs.discard("job_id_tmp_1")
  336. assert submission_1.pending_jobs.data == set(["job_id_1", "job_id_2", "job_id_tmp_2"])
  337. assert submission_2.pending_jobs.data == set(["job_id_1", "job_id_2", "job_id_tmp_2"])
  338. submission_2.pending_jobs.discard("job_id_tmp_2")
  339. assert submission_1.pending_jobs.data == set(["job_id_1", "job_id_2"])
  340. assert submission_2.pending_jobs.data == set(["job_id_1", "job_id_2"])
  341. submission_1.pending_jobs.add("job_id_tmp_1")
  342. submission_2.pending_jobs.add("job_id_tmp_2")
  343. assert submission_1.pending_jobs.data == set(["job_id_1", "job_id_2", "job_id_tmp_1", "job_id_tmp_2"])
  344. assert submission_2.pending_jobs.data == set(["job_id_1", "job_id_2", "job_id_tmp_1", "job_id_tmp_2"])
  345. submission_1.pending_jobs.pop()
  346. assert len(submission_1.pending_jobs.data) == 3
  347. assert len(submission_2.pending_jobs.data) == 3
  348. submission_2.pending_jobs.pop()
  349. assert len(submission_1.pending_jobs.data) == 2
  350. assert len(submission_2.pending_jobs.data) == 2
  351. submission_1.pending_jobs.clear()
  352. assert len(submission_1.pending_jobs.data) == 0
  353. assert len(submission_2.pending_jobs.data) == 0
  354. def test_auto_set_and_reload_properties():
  355. task = Task(config_id="name_1", properties={}, function=print, id=TaskId("task_1"))
  356. submission_1 = Submission(task.id, task._ID_PREFIX, task.config_id, properties={})
  357. _TaskManagerFactory._build_manager()._set(task)
  358. _SubmissionManagerFactory._build_manager()._set(submission_1)
  359. submission_2 = _SubmissionManagerFactory._build_manager()._get(submission_1)
  360. # auto set & reload on properties attribute
  361. assert submission_1.properties == {}
  362. assert submission_2.properties == {}
  363. submission_1._properties["qux"] = 4
  364. assert submission_1.properties["qux"] == 4
  365. assert submission_2.properties["qux"] == 4
  366. assert submission_1.properties == {"qux": 4}
  367. assert submission_2.properties == {"qux": 4}
  368. submission_2._properties["qux"] = 5
  369. assert submission_1.properties["qux"] == 5
  370. assert submission_2.properties["qux"] == 5
  371. submission_1.properties["temp_key_1"] = "temp_value_1"
  372. submission_1.properties["temp_key_2"] = "temp_value_2"
  373. assert submission_1.properties == {"qux": 5, "temp_key_1": "temp_value_1", "temp_key_2": "temp_value_2"}
  374. assert submission_2.properties == {"qux": 5, "temp_key_1": "temp_value_1", "temp_key_2": "temp_value_2"}
  375. submission_1.properties.pop("temp_key_1")
  376. assert "temp_key_1" not in submission_1.properties.keys()
  377. assert "temp_key_1" not in submission_1.properties.keys()
  378. assert submission_1.properties == {"qux": 5, "temp_key_2": "temp_value_2"}
  379. assert submission_2.properties == {"qux": 5, "temp_key_2": "temp_value_2"}
  380. submission_2.properties.pop("temp_key_2")
  381. assert submission_1.properties == {"qux": 5}
  382. assert submission_2.properties == {"qux": 5}
  383. assert "temp_key_2" not in submission_1.properties.keys()
  384. assert "temp_key_2" not in submission_2.properties.keys()
  385. submission_1.properties["temp_key_3"] = 0
  386. assert submission_1.properties == {"qux": 5, "temp_key_3": 0}
  387. assert submission_2.properties == {"qux": 5, "temp_key_3": 0}
  388. submission_1.properties.update({"temp_key_3": 1})
  389. assert submission_1.properties == {"qux": 5, "temp_key_3": 1}
  390. assert submission_2.properties == {"qux": 5, "temp_key_3": 1}
  391. submission_1.properties.update(dict())
  392. assert submission_1.properties == {"qux": 5, "temp_key_3": 1}
  393. assert submission_2.properties == {"qux": 5, "temp_key_3": 1}
  394. submission_1.properties["temp_key_4"] = 0
  395. submission_1.properties["temp_key_5"] = 0
  396. with submission_1 as submission:
  397. assert submission.properties["qux"] == 5
  398. assert submission.properties["temp_key_3"] == 1
  399. assert submission.properties["temp_key_4"] == 0
  400. assert submission.properties["temp_key_5"] == 0
  401. submission.properties["qux"] = 9
  402. submission.properties.pop("temp_key_3")
  403. submission.properties.pop("temp_key_4")
  404. submission.properties.update({"temp_key_4": 1})
  405. submission.properties.update({"temp_key_5": 2})
  406. submission.properties.pop("temp_key_5")
  407. submission.properties.update(dict())
  408. assert submission.properties["qux"] == 5
  409. assert submission.properties["temp_key_3"] == 1
  410. assert submission.properties["temp_key_4"] == 0
  411. assert submission.properties["temp_key_5"] == 0
  412. assert submission_1.properties["qux"] == 9
  413. assert "temp_key_3" not in submission_1.properties.keys()
  414. assert submission_1.properties["temp_key_4"] == 1
  415. assert "temp_key_5" not in submission_1.properties.keys()
  416. @pytest.mark.parametrize(
  417. "job_statuses, expected_submission_statuses",
  418. [
  419. (
  420. [Status.SUBMITTED, Status.PENDING, Status.RUNNING, Status.COMPLETED],
  421. [SubmissionStatus.PENDING, SubmissionStatus.PENDING, SubmissionStatus.RUNNING, SubmissionStatus.COMPLETED],
  422. ),
  423. (
  424. [Status.SUBMITTED, Status.PENDING, Status.RUNNING, Status.SKIPPED],
  425. [SubmissionStatus.PENDING, SubmissionStatus.PENDING, SubmissionStatus.RUNNING, SubmissionStatus.COMPLETED],
  426. ),
  427. (
  428. [Status.SUBMITTED, Status.PENDING, Status.RUNNING, Status.FAILED],
  429. [SubmissionStatus.PENDING, SubmissionStatus.PENDING, SubmissionStatus.RUNNING, SubmissionStatus.FAILED],
  430. ),
  431. (
  432. [Status.SUBMITTED, Status.PENDING, Status.CANCELED],
  433. [SubmissionStatus.PENDING, SubmissionStatus.PENDING, SubmissionStatus.CANCELED],
  434. ),
  435. (
  436. [Status.SUBMITTED, Status.PENDING, Status.RUNNING, Status.CANCELED],
  437. [SubmissionStatus.PENDING, SubmissionStatus.PENDING, SubmissionStatus.RUNNING, SubmissionStatus.CANCELED],
  438. ),
  439. ([Status.SUBMITTED, Status.BLOCKED], [SubmissionStatus.PENDING, SubmissionStatus.BLOCKED]),
  440. ([Status.SUBMITTED, Status.SKIPPED], [SubmissionStatus.PENDING, SubmissionStatus.COMPLETED]),
  441. ],
  442. )
  443. def test_update_submission_status_with_single_job_completed(job_statuses, expected_submission_statuses):
  444. job = MockJob("job_id", Status.SUBMITTED)
  445. submission = Submission("submission_id", "ENTITY_TYPE", "entity_config_id")
  446. assert submission.submission_status == SubmissionStatus.SUBMITTED
  447. for job_status, submission_status in zip(job_statuses, expected_submission_statuses):
  448. job.status = job_status
  449. submission._update_submission_status(job)
  450. assert submission.submission_status == submission_status
  451. def __test_update_submission_status_with_two_jobs(job_ids, job_statuses, expected_submission_statuses):
  452. jobs = {job_id: MockJob(job_id, Status.SUBMITTED) for job_id in job_ids}
  453. submission = Submission("submission_id", "ENTITY_TYPE", "entity_config_id")
  454. assert submission.submission_status == SubmissionStatus.SUBMITTED
  455. for (job_id, job_status), submission_status in zip(job_statuses, expected_submission_statuses):
  456. job = jobs[job_id]
  457. job.status = job_status
  458. submission._update_submission_status(job)
  459. assert submission.submission_status == submission_status
  460. @pytest.mark.parametrize(
  461. "job_ids, job_statuses, expected_submission_statuses",
  462. [
  463. (
  464. ["job_1", "job_2"],
  465. [
  466. ("job_1", Status.SUBMITTED),
  467. ("job_2", Status.SUBMITTED),
  468. ("job_1", Status.PENDING),
  469. ("job_2", Status.PENDING),
  470. ("job_1", Status.RUNNING),
  471. ("job_2", Status.RUNNING),
  472. ("job_1", Status.COMPLETED),
  473. ("job_2", Status.COMPLETED),
  474. ],
  475. [
  476. SubmissionStatus.PENDING,
  477. SubmissionStatus.PENDING,
  478. SubmissionStatus.PENDING,
  479. SubmissionStatus.PENDING,
  480. SubmissionStatus.RUNNING,
  481. SubmissionStatus.RUNNING,
  482. SubmissionStatus.RUNNING,
  483. SubmissionStatus.COMPLETED,
  484. ],
  485. ),
  486. (
  487. ["job_1", "job_2"],
  488. [
  489. ("job_1", Status.SUBMITTED),
  490. ("job_2", Status.SUBMITTED),
  491. ("job_1", Status.PENDING),
  492. ("job_1", Status.RUNNING),
  493. ("job_2", Status.PENDING),
  494. ("job_2", Status.RUNNING),
  495. ("job_1", Status.COMPLETED),
  496. ("job_2", Status.COMPLETED),
  497. ],
  498. [
  499. SubmissionStatus.PENDING,
  500. SubmissionStatus.PENDING,
  501. SubmissionStatus.PENDING,
  502. SubmissionStatus.RUNNING,
  503. SubmissionStatus.RUNNING,
  504. SubmissionStatus.RUNNING,
  505. SubmissionStatus.RUNNING,
  506. SubmissionStatus.COMPLETED,
  507. ],
  508. ),
  509. (
  510. ["job_1", "job_2"],
  511. [
  512. ("job_1", Status.SUBMITTED),
  513. ("job_2", Status.SUBMITTED),
  514. ("job_1", Status.BLOCKED),
  515. ("job_2", Status.PENDING),
  516. ("job_2", Status.RUNNING),
  517. ("job_2", Status.COMPLETED),
  518. ("job_1", Status.PENDING),
  519. ("job_1", Status.RUNNING),
  520. ("job_1", Status.COMPLETED),
  521. ],
  522. [
  523. SubmissionStatus.PENDING,
  524. SubmissionStatus.PENDING,
  525. SubmissionStatus.PENDING,
  526. SubmissionStatus.PENDING,
  527. SubmissionStatus.RUNNING,
  528. SubmissionStatus.BLOCKED,
  529. SubmissionStatus.PENDING,
  530. SubmissionStatus.RUNNING,
  531. SubmissionStatus.COMPLETED,
  532. ],
  533. ),
  534. ],
  535. )
  536. def test_update_submission_status_with_two_jobs_completed(job_ids, job_statuses, expected_submission_statuses):
  537. __test_update_submission_status_with_two_jobs(job_ids, job_statuses, expected_submission_statuses)
  538. @pytest.mark.parametrize(
  539. "job_ids, job_statuses, expected_submission_statuses",
  540. [
  541. (
  542. ["job_1", "job_2"],
  543. [
  544. ("job_1", Status.SUBMITTED),
  545. ("job_2", Status.SUBMITTED),
  546. ("job_1", Status.PENDING),
  547. ("job_2", Status.PENDING),
  548. ("job_1", Status.RUNNING),
  549. ("job_2", Status.SKIPPED),
  550. ("job_1", Status.COMPLETED),
  551. ],
  552. [
  553. SubmissionStatus.PENDING,
  554. SubmissionStatus.PENDING,
  555. SubmissionStatus.PENDING,
  556. SubmissionStatus.PENDING,
  557. SubmissionStatus.RUNNING,
  558. SubmissionStatus.RUNNING,
  559. SubmissionStatus.COMPLETED,
  560. ],
  561. ),
  562. (
  563. ["job_1", "job_2"],
  564. [
  565. ("job_1", Status.SUBMITTED),
  566. ("job_2", Status.SUBMITTED),
  567. ("job_1", Status.PENDING),
  568. ("job_1", Status.RUNNING),
  569. ("job_2", Status.PENDING),
  570. ("job_2", Status.SKIPPED),
  571. ("job_1", Status.COMPLETED),
  572. ],
  573. [
  574. SubmissionStatus.PENDING,
  575. SubmissionStatus.PENDING,
  576. SubmissionStatus.PENDING,
  577. SubmissionStatus.RUNNING,
  578. SubmissionStatus.RUNNING,
  579. SubmissionStatus.RUNNING,
  580. SubmissionStatus.COMPLETED,
  581. ],
  582. ),
  583. (
  584. ["job_1", "job_2"],
  585. [
  586. ("job_1", Status.SUBMITTED),
  587. ("job_2", Status.SUBMITTED),
  588. ("job_1", Status.BLOCKED),
  589. ("job_2", Status.PENDING),
  590. ("job_2", Status.RUNNING),
  591. ("job_2", Status.COMPLETED),
  592. ("job_1", Status.PENDING),
  593. ("job_1", Status.SKIPPED),
  594. ],
  595. [
  596. SubmissionStatus.PENDING,
  597. SubmissionStatus.PENDING,
  598. SubmissionStatus.PENDING,
  599. SubmissionStatus.PENDING,
  600. SubmissionStatus.RUNNING,
  601. SubmissionStatus.BLOCKED,
  602. SubmissionStatus.PENDING,
  603. SubmissionStatus.COMPLETED,
  604. ],
  605. ),
  606. (
  607. ["job_1", "job_2"],
  608. [
  609. ("job_1", Status.SUBMITTED),
  610. ("job_2", Status.SUBMITTED),
  611. ("job_1", Status.PENDING),
  612. ("job_2", Status.PENDING),
  613. ("job_1", Status.SKIPPED),
  614. ("job_2", Status.SKIPPED),
  615. ],
  616. [
  617. SubmissionStatus.PENDING,
  618. SubmissionStatus.PENDING,
  619. SubmissionStatus.PENDING,
  620. SubmissionStatus.PENDING,
  621. SubmissionStatus.PENDING,
  622. SubmissionStatus.COMPLETED,
  623. ],
  624. ),
  625. (
  626. ["job_1", "job_2"],
  627. [
  628. ("job_1", Status.SUBMITTED),
  629. ("job_2", Status.SUBMITTED),
  630. ("job_1", Status.PENDING),
  631. ("job_1", Status.SKIPPED),
  632. ("job_2", Status.PENDING),
  633. ("job_2", Status.SKIPPED),
  634. ],
  635. [
  636. SubmissionStatus.PENDING,
  637. SubmissionStatus.PENDING,
  638. SubmissionStatus.PENDING,
  639. SubmissionStatus.PENDING,
  640. SubmissionStatus.PENDING,
  641. SubmissionStatus.COMPLETED,
  642. ],
  643. ),
  644. (
  645. ["job_1", "job_2"],
  646. [
  647. ("job_1", Status.SUBMITTED),
  648. ("job_2", Status.SUBMITTED),
  649. ("job_1", Status.BLOCKED),
  650. ("job_2", Status.PENDING),
  651. ("job_2", Status.SKIPPED),
  652. ("job_1", Status.PENDING),
  653. ("job_1", Status.SKIPPED),
  654. ],
  655. [
  656. SubmissionStatus.PENDING,
  657. SubmissionStatus.PENDING,
  658. SubmissionStatus.PENDING,
  659. SubmissionStatus.PENDING,
  660. SubmissionStatus.BLOCKED,
  661. SubmissionStatus.PENDING,
  662. SubmissionStatus.COMPLETED,
  663. ],
  664. ),
  665. ],
  666. )
  667. def test_update_submission_status_with_two_jobs_skipped(job_ids, job_statuses, expected_submission_statuses):
  668. __test_update_submission_status_with_two_jobs(job_ids, job_statuses, expected_submission_statuses)
  669. @pytest.mark.parametrize(
  670. "job_ids, job_statuses, expected_submission_statuses",
  671. [
  672. (
  673. ["job_1", "job_2"],
  674. [
  675. ("job_1", Status.SUBMITTED),
  676. ("job_2", Status.SUBMITTED),
  677. ("job_1", Status.PENDING),
  678. ("job_2", Status.PENDING),
  679. ("job_1", Status.RUNNING),
  680. ("job_2", Status.RUNNING),
  681. ("job_1", Status.FAILED),
  682. ("job_2", Status.COMPLETED),
  683. ],
  684. [
  685. SubmissionStatus.PENDING,
  686. SubmissionStatus.PENDING,
  687. SubmissionStatus.PENDING,
  688. SubmissionStatus.PENDING,
  689. SubmissionStatus.RUNNING,
  690. SubmissionStatus.RUNNING,
  691. SubmissionStatus.FAILED,
  692. SubmissionStatus.FAILED,
  693. ],
  694. ),
  695. (
  696. ["job_1", "job_2"],
  697. [
  698. ("job_1", Status.SUBMITTED),
  699. ("job_2", Status.SUBMITTED),
  700. ("job_1", Status.PENDING),
  701. ("job_1", Status.RUNNING),
  702. ("job_2", Status.PENDING),
  703. ("job_2", Status.RUNNING),
  704. ("job_1", Status.COMPLETED),
  705. ("job_2", Status.FAILED),
  706. ],
  707. [
  708. SubmissionStatus.PENDING,
  709. SubmissionStatus.PENDING,
  710. SubmissionStatus.PENDING,
  711. SubmissionStatus.RUNNING,
  712. SubmissionStatus.RUNNING,
  713. SubmissionStatus.RUNNING,
  714. SubmissionStatus.RUNNING,
  715. SubmissionStatus.FAILED,
  716. ],
  717. ),
  718. (
  719. ["job_1", "job_2"],
  720. [
  721. ("job_1", Status.SUBMITTED),
  722. ("job_2", Status.SUBMITTED),
  723. ("job_1", Status.BLOCKED),
  724. ("job_2", Status.PENDING),
  725. ("job_2", Status.RUNNING),
  726. ("job_2", Status.FAILED),
  727. ("job_1", Status.ABANDONED),
  728. ],
  729. [
  730. SubmissionStatus.PENDING,
  731. SubmissionStatus.PENDING,
  732. SubmissionStatus.PENDING,
  733. SubmissionStatus.PENDING,
  734. SubmissionStatus.RUNNING,
  735. SubmissionStatus.FAILED,
  736. SubmissionStatus.FAILED,
  737. ],
  738. ),
  739. ],
  740. )
  741. def test_update_submission_status_with_two_jobs_failed(job_ids, job_statuses, expected_submission_statuses):
  742. __test_update_submission_status_with_two_jobs(job_ids, job_statuses, expected_submission_statuses)
  743. @pytest.mark.parametrize(
  744. "job_ids, job_statuses, expected_submission_statuses",
  745. [
  746. (
  747. ["job_1", "job_2"],
  748. [
  749. ("job_1", Status.SUBMITTED),
  750. ("job_2", Status.SUBMITTED),
  751. ("job_1", Status.PENDING),
  752. ("job_2", Status.PENDING),
  753. ("job_1", Status.RUNNING),
  754. ("job_2", Status.RUNNING),
  755. ("job_1", Status.CANCELED),
  756. ("job_2", Status.COMPLETED),
  757. ],
  758. [
  759. SubmissionStatus.PENDING,
  760. SubmissionStatus.PENDING,
  761. SubmissionStatus.PENDING,
  762. SubmissionStatus.PENDING,
  763. SubmissionStatus.RUNNING,
  764. SubmissionStatus.RUNNING,
  765. SubmissionStatus.CANCELED,
  766. SubmissionStatus.CANCELED,
  767. ],
  768. ),
  769. (
  770. ["job_1", "job_2"],
  771. [
  772. ("job_1", Status.SUBMITTED),
  773. ("job_2", Status.SUBMITTED),
  774. ("job_1", Status.PENDING),
  775. ("job_1", Status.RUNNING),
  776. ("job_2", Status.PENDING),
  777. ("job_2", Status.RUNNING),
  778. ("job_1", Status.COMPLETED),
  779. ("job_2", Status.CANCELED),
  780. ],
  781. [
  782. SubmissionStatus.PENDING,
  783. SubmissionStatus.PENDING,
  784. SubmissionStatus.PENDING,
  785. SubmissionStatus.RUNNING,
  786. SubmissionStatus.RUNNING,
  787. SubmissionStatus.RUNNING,
  788. SubmissionStatus.RUNNING,
  789. SubmissionStatus.CANCELED,
  790. ],
  791. ),
  792. (
  793. ["job_1", "job_2"],
  794. [
  795. ("job_1", Status.SUBMITTED),
  796. ("job_2", Status.SUBMITTED),
  797. ("job_1", Status.BLOCKED),
  798. ("job_2", Status.PENDING),
  799. ("job_2", Status.RUNNING),
  800. ("job_2", Status.CANCELED),
  801. ("job_1", Status.ABANDONED),
  802. ],
  803. [
  804. SubmissionStatus.PENDING,
  805. SubmissionStatus.PENDING,
  806. SubmissionStatus.PENDING,
  807. SubmissionStatus.PENDING,
  808. SubmissionStatus.RUNNING,
  809. SubmissionStatus.CANCELED,
  810. SubmissionStatus.CANCELED,
  811. ],
  812. ),
  813. ],
  814. )
  815. def test_update_submission_status_with_two_jobs_canceled(job_ids, job_statuses, expected_submission_statuses):
  816. __test_update_submission_status_with_two_jobs(job_ids, job_statuses, expected_submission_statuses)
  817. def test_is_finished():
  818. submission_manager = _SubmissionManagerFactory._build_manager()
  819. submission = Submission("entity_id", "entity_type", "entity_config_id", "submission_id")
  820. submission_manager._set(submission)
  821. assert len(submission_manager._get_all()) == 1
  822. assert submission._submission_status == SubmissionStatus.SUBMITTED
  823. assert not submission.is_finished()
  824. submission.submission_status = SubmissionStatus.UNDEFINED
  825. assert submission.submission_status == SubmissionStatus.UNDEFINED
  826. assert not submission.is_finished()
  827. submission.submission_status = SubmissionStatus.CANCELED
  828. assert submission.submission_status == SubmissionStatus.CANCELED
  829. assert submission.is_finished()
  830. submission.submission_status = SubmissionStatus.FAILED
  831. assert submission.submission_status == SubmissionStatus.FAILED
  832. assert submission.is_finished()
  833. submission.submission_status = SubmissionStatus.BLOCKED
  834. assert submission.submission_status == SubmissionStatus.BLOCKED
  835. assert not submission.is_finished()
  836. submission.submission_status = SubmissionStatus.RUNNING
  837. assert submission.submission_status == SubmissionStatus.RUNNING
  838. assert not submission.is_finished()
  839. submission.submission_status = SubmissionStatus.PENDING
  840. assert submission.submission_status == SubmissionStatus.PENDING
  841. assert not submission.is_finished()
  842. submission.submission_status = SubmissionStatus.COMPLETED
  843. assert submission.submission_status == SubmissionStatus.COMPLETED
  844. assert submission.is_finished()