Warning, file /panda-server/pandaserver/taskbuffer/tests/key_reads_tests.py was not indexed
or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001
0002 import datetime
0003 import unittest
0004 from typing import Any
0005 from unittest import mock
0006
0007 from pandaserver.taskbuffer import task_split_rules
0008 from pandaserver.taskbuffer.DatasetSpec import DatasetSpec
0009 from pandaserver.taskbuffer.db_proxy_mods import job_standalone_module
0010 from pandaserver.taskbuffer.db_proxy_mods.job_standalone_module import (
0011 JobStandaloneModule,
0012 )
0013 from pandaserver.taskbuffer.db_proxy_mods.misc_standalone_module import (
0014 MiscStandaloneModule,
0015 )
0016 from pandaserver.taskbuffer.db_proxy_mods.task_utils_module import TaskUtilsModule
0017 from pandaserver.taskbuffer.JediTaskSpec import JediTaskSpec
0018 from pandaserver.taskbuffer.JobSpec import JobSpec
0019 from pandaserver.taskbuffer.TaskBuffer import TaskBuffer
0020
0021 LOST = "ORA-03113: end-of-file on communication channel"
0022
0023
0024 class TestPeekRaiseError(unittest.TestCase):
0025 def setUp(self) -> None:
0026 self.proxy = mock.MagicMock()
0027 self.proxy.cur.execute.side_effect = Exception(LOST)
0028 patcher = mock.patch.object(job_standalone_module.time, "sleep")
0029 self.sleep = patcher.start()
0030 self.addCleanup(patcher.stop)
0031
0032 def test_peek_job_raises_at_once(self) -> None:
0033 with self.assertRaisesRegex(Exception, "ORA-03113"):
0034 JobStandaloneModule.peekJob(self.proxy, 7000000000, True, True, True, True, forAnal=True, raise_error=True)
0035 self.assertEqual(self.proxy.cur.execute.call_count, 1)
0036 self.sleep.assert_not_called()
0037
0038 def test_peek_job_as_before_without(self) -> None:
0039 self.assertIsNone(JobStandaloneModule.peekJob(self.proxy, 7000000000, True, True, True, True, forAnal=True))
0040 self.assertEqual(self.proxy.cur.execute.call_count, 3)
0041 job = JobStandaloneModule.peekJob(self.proxy, 7000000000, True, True, True, True)
0042 self.assertIsInstance(job, JobSpec)
0043 self.assertEqual(job.jobStatus, "unknown")
0044
0045 def test_peek_job_log(self) -> None:
0046 with self.assertRaisesRegex(Exception, "ORA-03113"):
0047 JobStandaloneModule.peekJobLog(self.proxy, 7000000000, 90, raise_error=True)
0048 self.assertIsNone(JobStandaloneModule.peekJobLog(self.proxy, 7000000000, 90))
0049
0050
0051 class TestGetFullJobStatus(unittest.TestCase):
0052 """Job 1 is live, 2 is nowhere, 3 a live table cannot be read for, and 4 the archive cannot be read for."""
0053
0054 def setUp(self) -> None:
0055 self.job = JobSpec()
0056 self.proxy = mock.MagicMock()
0057
0058 def peek_job(job_id: int, *args: Any, raise_error: bool = False) -> JobSpec | None:
0059 if job_id == 3 and raise_error:
0060 raise Exception(LOST)
0061 return self.job if job_id == 1 else None
0062
0063 def peek_job_log(job_id: int, days: int | None, raise_error: bool = False) -> JobSpec | None:
0064 if job_id == 4 and raise_error:
0065 raise Exception("ORA-01013: user requested cancel of current operation")
0066 return None
0067
0068 self.proxy.peekJob.side_effect = peek_job
0069 self.proxy.peekJobLog.side_effect = peek_job_log
0070 self.task_buffer = TaskBuffer.__new__(TaskBuffer)
0071 self.task_buffer.proxyPool = mock.MagicMock()
0072 self.task_buffer.proxyPool.get.return_value.__enter__.return_value = self.proxy
0073
0074 def test_errors_reported(self) -> None:
0075 jobs = self.task_buffer.getFullJobStatus([1, 2, 3, 4], report_errors=True)
0076 self.assertEqual(jobs, [self.job, None, {"error": "ORA-03113"}, {"error": "ORA-01013"}])
0077
0078 self.assertEqual([call.args[0] for call in self.proxy.peekJobLog.call_args_list], [2, 4])
0079
0080 def test_errors_as_not_found_by_default(self) -> None:
0081 self.assertEqual(self.task_buffer.getFullJobStatus([1, 2, 3, 4]), [self.job, None, None, None])
0082 self.assertEqual({call.kwargs["raise_error"] for call in self.proxy.peekJob.call_args_list}, {False})
0083
0084 def test_unexpected_error_raised_by_default(self) -> None:
0085 self.proxy.peekJob.side_effect = ValueError("broken")
0086 with self.assertRaises(ValueError):
0087 self.task_buffer.getFullJobStatus([1])
0088
0089
0090 class TestGetDatasetsByName(unittest.TestCase):
0091 AS_OF = datetime.datetime(2026, 10, 14, 9, 0, 0)
0092 RETAINED_FROM = datetime.datetime(2026, 7, 1)
0093
0094 def setUp(self) -> None:
0095 self.proxy = mock.MagicMock()
0096 self.proxy.get_db_utc_now.return_value = self.AS_OF
0097 self.proxy.get_partition_window.return_value = (5, self.RETAINED_FROM)
0098 self.proxy._commit.return_value = True
0099
0100 def test_rows(self) -> None:
0101 columns = DatasetSpec.columnNames().split(",")
0102 row = tuple(f"value of {column}" for column in columns)
0103 self.proxy.cur.fetchall.return_value = [row]
0104 success, message, data = MiscStandaloneModule.get_datasets_by_name(self.proxy, ["a_sub1", "b_sub2"], 1000)
0105 self.assertTrue(success, message)
0106 self.assertEqual(data, {"rows": [dict(zip(columns, row))], "as_of": self.AS_OF, "retained_from": self.RETAINED_FROM, "partitions": 5, "budget": 1000})
0107 self.assertIn("creationdate", data["rows"][0])
0108 sql, var_map = self.proxy.cur.execute.call_args[0]
0109 self.assertIn("FROM ATLAS_PANDA.Datasets WHERE name IN (", sql)
0110 self.assertEqual(sorted(var_map.values()), ["a_sub1", "b_sub2"])
0111
0112 def test_over_budget(self) -> None:
0113 success, message, data = MiscStandaloneModule.get_datasets_by_name(self.proxy, [f"a_sub{i}" for i in range(201)], 1000)
0114 self.assertFalse(success)
0115 self.assertEqual(data, {"rejected": "probe_budget", "keys": 201, "partitions": 5, "budget": 1000})
0116 self.proxy.cur.execute.assert_not_called()
0117
0118 def test_database_error(self) -> None:
0119 self.proxy.cur.execute.side_effect = Exception("ORA-00942: table or view does not exist")
0120 success, message, data = MiscStandaloneModule.get_datasets_by_name(self.proxy, ["a_sub1"], 1000)
0121 self.assertEqual((success, data), (False, {"error": "ORA-00942"}))
0122
0123
0124 class TestTaskDetailsSplitRule(unittest.TestCase):
0125 def _details(self, split_rule: str | None) -> dict[str, Any]:
0126 row: list[str | None] = [None] * len(JediTaskSpec.attributes)
0127 row[JediTaskSpec.attributes.index("splitRule")] = split_rule
0128 proxy = mock.MagicMock()
0129 proxy.cur.fetchone.side_effect = [tuple(row), (0, 0, 0, 0)]
0130 proxy.getClobObj.side_effect = [(True, [["template"]]), (True, [['{"cliParams": "prun"}']])]
0131 details: dict[str, Any] = TaskUtilsModule.get_task_details_json(proxy, 1)
0132 return details
0133
0134 def test_raw_kept(self) -> None:
0135 raw = "CI=1,MF=1"
0136 details = self._details(raw)
0137 self.assertEqual(details["split_rule_raw"], raw)
0138 self.assertEqual(details["splitRule"], task_split_rules.decode_split_rule(raw))
0139 self.assertNotEqual(details["splitRule"], raw)
0140
0141 def test_null(self) -> None:
0142 details = self._details(None)
0143 self.assertIsNone(details["split_rule_raw"])
0144 self.assertIsNone(details["splitRule"])
0145
0146
0147 if __name__ == "__main__":
0148 unittest.main()