test_submission.py 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853
  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 submission_status attribute
  256. assert submission_1.submission_status == SubmissionStatus.SUBMITTED
  257. assert submission_2.submission_status == SubmissionStatus.SUBMITTED
  258. submission_1.submission_status = SubmissionStatus.BLOCKED
  259. assert submission_1.submission_status == SubmissionStatus.BLOCKED
  260. assert submission_2.submission_status == SubmissionStatus.BLOCKED
  261. submission_2.submission_status = SubmissionStatus.COMPLETED
  262. assert submission_1.submission_status == SubmissionStatus.COMPLETED
  263. assert submission_2.submission_status == SubmissionStatus.COMPLETED
  264. # auto set & reload on properties attribute
  265. assert submission_1.properties == {}
  266. assert submission_2.properties == {}
  267. submission_1._properties["qux"] = 4
  268. assert submission_1.properties["qux"] == 4
  269. assert submission_2.properties["qux"] == 4
  270. assert submission_1.properties == {"qux": 4}
  271. assert submission_2.properties == {"qux": 4}
  272. submission_2._properties["qux"] = 5
  273. assert submission_1.properties["qux"] == 5
  274. assert submission_2.properties["qux"] == 5
  275. submission_1.properties["temp_key_1"] = "temp_value_1"
  276. submission_1.properties["temp_key_2"] = "temp_value_2"
  277. assert submission_1.properties == {
  278. "qux": 5,
  279. "temp_key_1": "temp_value_1",
  280. "temp_key_2": "temp_value_2",
  281. }
  282. assert submission_2.properties == {
  283. "qux": 5,
  284. "temp_key_1": "temp_value_1",
  285. "temp_key_2": "temp_value_2",
  286. }
  287. submission_1.properties.pop("temp_key_1")
  288. assert "temp_key_1" not in submission_1.properties.keys()
  289. assert "temp_key_1" not in submission_1.properties.keys()
  290. assert submission_1.properties == {
  291. "qux": 5,
  292. "temp_key_2": "temp_value_2",
  293. }
  294. assert submission_2.properties == {
  295. "qux": 5,
  296. "temp_key_2": "temp_value_2",
  297. }
  298. submission_2.properties.pop("temp_key_2")
  299. assert submission_1.properties == {"qux": 5}
  300. assert submission_2.properties == {"qux": 5}
  301. assert "temp_key_2" not in submission_1.properties.keys()
  302. assert "temp_key_2" not in submission_2.properties.keys()
  303. submission_1.properties["temp_key_3"] = 0
  304. assert submission_1.properties == {"qux": 5, "temp_key_3": 0}
  305. assert submission_2.properties == {"qux": 5, "temp_key_3": 0}
  306. submission_1.properties.update({"temp_key_3": 1})
  307. assert submission_1.properties == {"qux": 5, "temp_key_3": 1}
  308. assert submission_2.properties == {"qux": 5, "temp_key_3": 1}
  309. submission_1.properties.update(dict())
  310. assert submission_1.properties == {"qux": 5, "temp_key_3": 1}
  311. assert submission_2.properties == {"qux": 5, "temp_key_3": 1}
  312. submission_1.properties["temp_key_4"] = 0
  313. submission_1.properties["temp_key_5"] = 0
  314. with submission_1 as submission:
  315. assert submission.jobs == [job_2, job_1]
  316. assert submission.submission_status == SubmissionStatus.COMPLETED
  317. assert submission.properties["qux"] == 5
  318. assert submission.properties["temp_key_3"] == 1
  319. assert submission.properties["temp_key_4"] == 0
  320. assert submission.properties["temp_key_5"] == 0
  321. submission.jobs = [job_1]
  322. submission.submission_status = SubmissionStatus.PENDING
  323. submission.properties["qux"] = 9
  324. submission.properties.pop("temp_key_3")
  325. submission.properties.pop("temp_key_4")
  326. submission.properties.update({"temp_key_4": 1})
  327. submission.properties.update({"temp_key_5": 2})
  328. submission.properties.pop("temp_key_5")
  329. submission.properties.update(dict())
  330. assert submission.jobs == [job_2, job_1]
  331. assert submission.submission_status == SubmissionStatus.COMPLETED
  332. assert submission.properties["qux"] == 5
  333. assert submission.properties["temp_key_3"] == 1
  334. assert submission.properties["temp_key_4"] == 0
  335. assert submission.properties["temp_key_5"] == 0
  336. assert submission_1.jobs == [job_1]
  337. assert submission_1.submission_status == SubmissionStatus.PENDING
  338. assert submission_2.jobs == [job_1]
  339. assert submission_2.submission_status == SubmissionStatus.PENDING
  340. assert submission_1.properties["qux"] == 9
  341. assert "temp_key_3" not in submission_1.properties.keys()
  342. assert submission_1.properties["temp_key_4"] == 1
  343. assert "temp_key_5" not in submission_1.properties.keys()
  344. @pytest.mark.parametrize(
  345. "job_statuses, expected_submission_statuses",
  346. [
  347. (
  348. [Status.SUBMITTED, Status.PENDING, Status.RUNNING, Status.COMPLETED],
  349. [SubmissionStatus.PENDING, SubmissionStatus.PENDING, SubmissionStatus.RUNNING, SubmissionStatus.COMPLETED],
  350. ),
  351. (
  352. [Status.SUBMITTED, Status.PENDING, Status.RUNNING, Status.SKIPPED],
  353. [SubmissionStatus.PENDING, SubmissionStatus.PENDING, SubmissionStatus.RUNNING, SubmissionStatus.COMPLETED],
  354. ),
  355. (
  356. [Status.SUBMITTED, Status.PENDING, Status.RUNNING, Status.FAILED],
  357. [SubmissionStatus.PENDING, SubmissionStatus.PENDING, SubmissionStatus.RUNNING, SubmissionStatus.FAILED],
  358. ),
  359. (
  360. [Status.SUBMITTED, Status.PENDING, Status.CANCELED],
  361. [SubmissionStatus.PENDING, SubmissionStatus.PENDING, SubmissionStatus.CANCELED],
  362. ),
  363. (
  364. [Status.SUBMITTED, Status.PENDING, Status.RUNNING, Status.CANCELED],
  365. [SubmissionStatus.PENDING, SubmissionStatus.PENDING, SubmissionStatus.RUNNING, SubmissionStatus.CANCELED],
  366. ),
  367. ([Status.SUBMITTED, Status.BLOCKED], [SubmissionStatus.PENDING, SubmissionStatus.BLOCKED]),
  368. ([Status.SUBMITTED, Status.SKIPPED], [SubmissionStatus.PENDING, SubmissionStatus.COMPLETED]),
  369. ],
  370. )
  371. def test_update_submission_status_with_single_job_completed(job_statuses, expected_submission_statuses):
  372. job = MockJob("job_id", Status.SUBMITTED)
  373. submission = Submission("submission_id", "ENTITY_TYPE", "entity_config_id")
  374. assert submission.submission_status == SubmissionStatus.SUBMITTED
  375. for job_status, submission_status in zip(job_statuses, expected_submission_statuses):
  376. job.status = job_status
  377. submission._update_submission_status(job)
  378. assert submission.submission_status == submission_status
  379. def __test_update_submission_status_with_two_jobs(job_ids, job_statuses, expected_submission_statuses):
  380. jobs = {job_id: MockJob(job_id, Status.SUBMITTED) for job_id in job_ids}
  381. submission = Submission("submission_id", "ENTITY_TYPE", "entity_config_id")
  382. assert submission.submission_status == SubmissionStatus.SUBMITTED
  383. for (job_id, job_status), submission_status in zip(job_statuses, expected_submission_statuses):
  384. job = jobs[job_id]
  385. job.status = job_status
  386. submission._update_submission_status(job)
  387. assert submission.submission_status == submission_status
  388. @pytest.mark.parametrize(
  389. "job_ids, job_statuses, expected_submission_statuses",
  390. [
  391. (
  392. ["job_1", "job_2"],
  393. [
  394. ("job_1", Status.SUBMITTED),
  395. ("job_2", Status.SUBMITTED),
  396. ("job_1", Status.PENDING),
  397. ("job_2", Status.PENDING),
  398. ("job_1", Status.RUNNING),
  399. ("job_2", Status.RUNNING),
  400. ("job_1", Status.COMPLETED),
  401. ("job_2", Status.COMPLETED),
  402. ],
  403. [
  404. SubmissionStatus.PENDING,
  405. SubmissionStatus.PENDING,
  406. SubmissionStatus.PENDING,
  407. SubmissionStatus.PENDING,
  408. SubmissionStatus.RUNNING,
  409. SubmissionStatus.RUNNING,
  410. SubmissionStatus.RUNNING,
  411. SubmissionStatus.COMPLETED,
  412. ],
  413. ),
  414. (
  415. ["job_1", "job_2"],
  416. [
  417. ("job_1", Status.SUBMITTED),
  418. ("job_2", Status.SUBMITTED),
  419. ("job_1", Status.PENDING),
  420. ("job_1", Status.RUNNING),
  421. ("job_2", Status.PENDING),
  422. ("job_2", Status.RUNNING),
  423. ("job_1", Status.COMPLETED),
  424. ("job_2", Status.COMPLETED),
  425. ],
  426. [
  427. SubmissionStatus.PENDING,
  428. SubmissionStatus.PENDING,
  429. SubmissionStatus.PENDING,
  430. SubmissionStatus.RUNNING,
  431. SubmissionStatus.RUNNING,
  432. SubmissionStatus.RUNNING,
  433. SubmissionStatus.RUNNING,
  434. SubmissionStatus.COMPLETED,
  435. ],
  436. ),
  437. (
  438. ["job_1", "job_2"],
  439. [
  440. ("job_1", Status.SUBMITTED),
  441. ("job_2", Status.SUBMITTED),
  442. ("job_1", Status.BLOCKED),
  443. ("job_2", Status.PENDING),
  444. ("job_2", Status.RUNNING),
  445. ("job_2", Status.COMPLETED),
  446. ("job_1", Status.PENDING),
  447. ("job_1", Status.RUNNING),
  448. ("job_1", Status.COMPLETED),
  449. ],
  450. [
  451. SubmissionStatus.PENDING,
  452. SubmissionStatus.PENDING,
  453. SubmissionStatus.PENDING,
  454. SubmissionStatus.PENDING,
  455. SubmissionStatus.RUNNING,
  456. SubmissionStatus.BLOCKED,
  457. SubmissionStatus.PENDING,
  458. SubmissionStatus.RUNNING,
  459. SubmissionStatus.COMPLETED,
  460. ],
  461. ),
  462. ],
  463. )
  464. def test_update_submission_status_with_two_jobs_completed(job_ids, job_statuses, expected_submission_statuses):
  465. __test_update_submission_status_with_two_jobs(job_ids, job_statuses, expected_submission_statuses)
  466. @pytest.mark.parametrize(
  467. "job_ids, job_statuses, expected_submission_statuses",
  468. [
  469. (
  470. ["job_1", "job_2"],
  471. [
  472. ("job_1", Status.SUBMITTED),
  473. ("job_2", Status.SUBMITTED),
  474. ("job_1", Status.PENDING),
  475. ("job_2", Status.PENDING),
  476. ("job_1", Status.RUNNING),
  477. ("job_2", Status.SKIPPED),
  478. ("job_1", Status.COMPLETED),
  479. ],
  480. [
  481. SubmissionStatus.PENDING,
  482. SubmissionStatus.PENDING,
  483. SubmissionStatus.PENDING,
  484. SubmissionStatus.PENDING,
  485. SubmissionStatus.RUNNING,
  486. SubmissionStatus.RUNNING,
  487. SubmissionStatus.COMPLETED,
  488. ],
  489. ),
  490. (
  491. ["job_1", "job_2"],
  492. [
  493. ("job_1", Status.SUBMITTED),
  494. ("job_2", Status.SUBMITTED),
  495. ("job_1", Status.PENDING),
  496. ("job_1", Status.RUNNING),
  497. ("job_2", Status.PENDING),
  498. ("job_2", Status.SKIPPED),
  499. ("job_1", Status.COMPLETED),
  500. ],
  501. [
  502. SubmissionStatus.PENDING,
  503. SubmissionStatus.PENDING,
  504. SubmissionStatus.PENDING,
  505. SubmissionStatus.RUNNING,
  506. SubmissionStatus.RUNNING,
  507. SubmissionStatus.RUNNING,
  508. SubmissionStatus.COMPLETED,
  509. ],
  510. ),
  511. (
  512. ["job_1", "job_2"],
  513. [
  514. ("job_1", Status.SUBMITTED),
  515. ("job_2", Status.SUBMITTED),
  516. ("job_1", Status.BLOCKED),
  517. ("job_2", Status.PENDING),
  518. ("job_2", Status.RUNNING),
  519. ("job_2", Status.COMPLETED),
  520. ("job_1", Status.PENDING),
  521. ("job_1", Status.SKIPPED),
  522. ],
  523. [
  524. SubmissionStatus.PENDING,
  525. SubmissionStatus.PENDING,
  526. SubmissionStatus.PENDING,
  527. SubmissionStatus.PENDING,
  528. SubmissionStatus.RUNNING,
  529. SubmissionStatus.BLOCKED,
  530. SubmissionStatus.PENDING,
  531. SubmissionStatus.COMPLETED,
  532. ],
  533. ),
  534. (
  535. ["job_1", "job_2"],
  536. [
  537. ("job_1", Status.SUBMITTED),
  538. ("job_2", Status.SUBMITTED),
  539. ("job_1", Status.PENDING),
  540. ("job_2", Status.PENDING),
  541. ("job_1", Status.SKIPPED),
  542. ("job_2", Status.SKIPPED),
  543. ],
  544. [
  545. SubmissionStatus.PENDING,
  546. SubmissionStatus.PENDING,
  547. SubmissionStatus.PENDING,
  548. SubmissionStatus.PENDING,
  549. SubmissionStatus.PENDING,
  550. SubmissionStatus.COMPLETED,
  551. ],
  552. ),
  553. (
  554. ["job_1", "job_2"],
  555. [
  556. ("job_1", Status.SUBMITTED),
  557. ("job_2", Status.SUBMITTED),
  558. ("job_1", Status.PENDING),
  559. ("job_1", Status.SKIPPED),
  560. ("job_2", Status.PENDING),
  561. ("job_2", Status.SKIPPED),
  562. ],
  563. [
  564. SubmissionStatus.PENDING,
  565. SubmissionStatus.PENDING,
  566. SubmissionStatus.PENDING,
  567. SubmissionStatus.PENDING,
  568. SubmissionStatus.PENDING,
  569. SubmissionStatus.COMPLETED,
  570. ],
  571. ),
  572. (
  573. ["job_1", "job_2"],
  574. [
  575. ("job_1", Status.SUBMITTED),
  576. ("job_2", Status.SUBMITTED),
  577. ("job_1", Status.BLOCKED),
  578. ("job_2", Status.PENDING),
  579. ("job_2", Status.SKIPPED),
  580. ("job_1", Status.PENDING),
  581. ("job_1", Status.SKIPPED),
  582. ],
  583. [
  584. SubmissionStatus.PENDING,
  585. SubmissionStatus.PENDING,
  586. SubmissionStatus.PENDING,
  587. SubmissionStatus.PENDING,
  588. SubmissionStatus.BLOCKED,
  589. SubmissionStatus.PENDING,
  590. SubmissionStatus.COMPLETED,
  591. ],
  592. ),
  593. ],
  594. )
  595. def test_update_submission_status_with_two_jobs_skipped(job_ids, job_statuses, expected_submission_statuses):
  596. __test_update_submission_status_with_two_jobs(job_ids, job_statuses, expected_submission_statuses)
  597. @pytest.mark.parametrize(
  598. "job_ids, job_statuses, expected_submission_statuses",
  599. [
  600. (
  601. ["job_1", "job_2"],
  602. [
  603. ("job_1", Status.SUBMITTED),
  604. ("job_2", Status.SUBMITTED),
  605. ("job_1", Status.PENDING),
  606. ("job_2", Status.PENDING),
  607. ("job_1", Status.RUNNING),
  608. ("job_2", Status.RUNNING),
  609. ("job_1", Status.FAILED),
  610. ("job_2", Status.COMPLETED),
  611. ],
  612. [
  613. SubmissionStatus.PENDING,
  614. SubmissionStatus.PENDING,
  615. SubmissionStatus.PENDING,
  616. SubmissionStatus.PENDING,
  617. SubmissionStatus.RUNNING,
  618. SubmissionStatus.RUNNING,
  619. SubmissionStatus.FAILED,
  620. SubmissionStatus.FAILED,
  621. ],
  622. ),
  623. (
  624. ["job_1", "job_2"],
  625. [
  626. ("job_1", Status.SUBMITTED),
  627. ("job_2", Status.SUBMITTED),
  628. ("job_1", Status.PENDING),
  629. ("job_1", Status.RUNNING),
  630. ("job_2", Status.PENDING),
  631. ("job_2", Status.RUNNING),
  632. ("job_1", Status.COMPLETED),
  633. ("job_2", Status.FAILED),
  634. ],
  635. [
  636. SubmissionStatus.PENDING,
  637. SubmissionStatus.PENDING,
  638. SubmissionStatus.PENDING,
  639. SubmissionStatus.RUNNING,
  640. SubmissionStatus.RUNNING,
  641. SubmissionStatus.RUNNING,
  642. SubmissionStatus.RUNNING,
  643. SubmissionStatus.FAILED,
  644. ],
  645. ),
  646. (
  647. ["job_1", "job_2"],
  648. [
  649. ("job_1", Status.SUBMITTED),
  650. ("job_2", Status.SUBMITTED),
  651. ("job_1", Status.BLOCKED),
  652. ("job_2", Status.PENDING),
  653. ("job_2", Status.RUNNING),
  654. ("job_2", Status.FAILED),
  655. ("job_1", Status.ABANDONED),
  656. ],
  657. [
  658. SubmissionStatus.PENDING,
  659. SubmissionStatus.PENDING,
  660. SubmissionStatus.PENDING,
  661. SubmissionStatus.PENDING,
  662. SubmissionStatus.RUNNING,
  663. SubmissionStatus.FAILED,
  664. SubmissionStatus.FAILED,
  665. ],
  666. ),
  667. ],
  668. )
  669. def test_update_submission_status_with_two_jobs_failed(job_ids, job_statuses, expected_submission_statuses):
  670. __test_update_submission_status_with_two_jobs(job_ids, job_statuses, expected_submission_statuses)
  671. @pytest.mark.parametrize(
  672. "job_ids, job_statuses, expected_submission_statuses",
  673. [
  674. (
  675. ["job_1", "job_2"],
  676. [
  677. ("job_1", Status.SUBMITTED),
  678. ("job_2", Status.SUBMITTED),
  679. ("job_1", Status.PENDING),
  680. ("job_2", Status.PENDING),
  681. ("job_1", Status.RUNNING),
  682. ("job_2", Status.RUNNING),
  683. ("job_1", Status.CANCELED),
  684. ("job_2", Status.COMPLETED),
  685. ],
  686. [
  687. SubmissionStatus.PENDING,
  688. SubmissionStatus.PENDING,
  689. SubmissionStatus.PENDING,
  690. SubmissionStatus.PENDING,
  691. SubmissionStatus.RUNNING,
  692. SubmissionStatus.RUNNING,
  693. SubmissionStatus.CANCELED,
  694. SubmissionStatus.CANCELED,
  695. ],
  696. ),
  697. (
  698. ["job_1", "job_2"],
  699. [
  700. ("job_1", Status.SUBMITTED),
  701. ("job_2", Status.SUBMITTED),
  702. ("job_1", Status.PENDING),
  703. ("job_1", Status.RUNNING),
  704. ("job_2", Status.PENDING),
  705. ("job_2", Status.RUNNING),
  706. ("job_1", Status.COMPLETED),
  707. ("job_2", Status.CANCELED),
  708. ],
  709. [
  710. SubmissionStatus.PENDING,
  711. SubmissionStatus.PENDING,
  712. SubmissionStatus.PENDING,
  713. SubmissionStatus.RUNNING,
  714. SubmissionStatus.RUNNING,
  715. SubmissionStatus.RUNNING,
  716. SubmissionStatus.RUNNING,
  717. SubmissionStatus.CANCELED,
  718. ],
  719. ),
  720. (
  721. ["job_1", "job_2"],
  722. [
  723. ("job_1", Status.SUBMITTED),
  724. ("job_2", Status.SUBMITTED),
  725. ("job_1", Status.BLOCKED),
  726. ("job_2", Status.PENDING),
  727. ("job_2", Status.RUNNING),
  728. ("job_2", Status.CANCELED),
  729. ("job_1", Status.ABANDONED),
  730. ],
  731. [
  732. SubmissionStatus.PENDING,
  733. SubmissionStatus.PENDING,
  734. SubmissionStatus.PENDING,
  735. SubmissionStatus.PENDING,
  736. SubmissionStatus.RUNNING,
  737. SubmissionStatus.CANCELED,
  738. SubmissionStatus.CANCELED,
  739. ],
  740. ),
  741. ],
  742. )
  743. def test_update_submission_status_with_two_jobs_canceled(job_ids, job_statuses, expected_submission_statuses):
  744. __test_update_submission_status_with_two_jobs(job_ids, job_statuses, expected_submission_statuses)
  745. def test_is_finished():
  746. submission_manager = _SubmissionManagerFactory._build_manager()
  747. submission = Submission("entity_id", "entity_type", "entity_config_id", "submission_id")
  748. submission_manager._set(submission)
  749. assert len(submission_manager._get_all()) == 1
  750. assert submission._submission_status == SubmissionStatus.SUBMITTED
  751. assert not submission.is_finished()
  752. submission.submission_status = SubmissionStatus.UNDEFINED
  753. assert submission.submission_status == SubmissionStatus.UNDEFINED
  754. assert not submission.is_finished()
  755. submission.submission_status = SubmissionStatus.CANCELED
  756. assert submission.submission_status == SubmissionStatus.CANCELED
  757. assert submission.is_finished()
  758. submission.submission_status = SubmissionStatus.FAILED
  759. assert submission.submission_status == SubmissionStatus.FAILED
  760. assert submission.is_finished()
  761. submission.submission_status = SubmissionStatus.BLOCKED
  762. assert submission.submission_status == SubmissionStatus.BLOCKED
  763. assert not submission.is_finished()
  764. submission.submission_status = SubmissionStatus.RUNNING
  765. assert submission.submission_status == SubmissionStatus.RUNNING
  766. assert not submission.is_finished()
  767. submission.submission_status = SubmissionStatus.PENDING
  768. assert submission.submission_status == SubmissionStatus.PENDING
  769. assert not submission.is_finished()
  770. submission.submission_status = SubmissionStatus.COMPLETED
  771. assert submission.submission_status == SubmissionStatus.COMPLETED
  772. assert submission.is_finished()