OpenOrchestrator 1.3.1__py3-none-any.whl → 2.0.0rc1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. OpenOrchestrator/__main__.py +66 -12
  2. OpenOrchestrator/common/connection_frame.py +10 -4
  3. OpenOrchestrator/database/base.py +8 -0
  4. OpenOrchestrator/database/constants.py +3 -15
  5. OpenOrchestrator/database/db_util.py +110 -37
  6. OpenOrchestrator/database/logs.py +3 -15
  7. OpenOrchestrator/database/queues.py +3 -15
  8. OpenOrchestrator/database/schedulers.py +32 -0
  9. OpenOrchestrator/database/triggers.py +7 -16
  10. OpenOrchestrator/orchestrator/application.py +13 -8
  11. OpenOrchestrator/orchestrator/datetime_input.py +2 -2
  12. OpenOrchestrator/orchestrator/popups/constant_popup.py +8 -6
  13. OpenOrchestrator/orchestrator/popups/credential_popup.py +10 -8
  14. OpenOrchestrator/orchestrator/popups/generic_popups.py +15 -2
  15. OpenOrchestrator/orchestrator/popups/trigger_popup.py +25 -14
  16. OpenOrchestrator/orchestrator/tabs/constants_tab.py +5 -2
  17. OpenOrchestrator/orchestrator/tabs/logging_tab.py +3 -0
  18. OpenOrchestrator/orchestrator/tabs/queue_tab.py +4 -1
  19. OpenOrchestrator/orchestrator/tabs/schedulers_tab.py +45 -0
  20. OpenOrchestrator/orchestrator/tabs/settings_tab.py +2 -5
  21. OpenOrchestrator/orchestrator/tabs/trigger_tab.py +9 -5
  22. OpenOrchestrator/orchestrator/test_helper.py +17 -0
  23. OpenOrchestrator/orchestrator_connection/connection.py +21 -4
  24. OpenOrchestrator/scheduler/application.py +3 -2
  25. OpenOrchestrator/scheduler/run_tab.py +16 -6
  26. OpenOrchestrator/scheduler/runner.py +51 -63
  27. OpenOrchestrator/scheduler/settings_tab.py +90 -14
  28. OpenOrchestrator/scheduler/util.py +8 -0
  29. OpenOrchestrator/tests/__init__.py +0 -0
  30. OpenOrchestrator/tests/db_test_util.py +40 -0
  31. OpenOrchestrator/tests/test_db_util.py +372 -0
  32. OpenOrchestrator/tests/test_orchestrator_connection.py +142 -0
  33. OpenOrchestrator/tests/test_trigger_polling.py +143 -0
  34. OpenOrchestrator/tests/ui_tests/__init__.py +0 -0
  35. OpenOrchestrator/tests/ui_tests/test_constants_tab.py +167 -0
  36. OpenOrchestrator/tests/ui_tests/test_logging_tab.py +180 -0
  37. OpenOrchestrator/tests/ui_tests/test_queues_tab.py +126 -0
  38. OpenOrchestrator/tests/ui_tests/test_schedulers_tab.py +47 -0
  39. OpenOrchestrator/tests/ui_tests/test_trigger_tab.py +243 -0
  40. OpenOrchestrator/tests/ui_tests/ui_util.py +151 -0
  41. openorchestrator-2.0.0rc1.dist-info/METADATA +158 -0
  42. openorchestrator-2.0.0rc1.dist-info/RECORD +55 -0
  43. {openorchestrator-1.3.1.dist-info → openorchestrator-2.0.0rc1.dist-info}/WHEEL +1 -1
  44. OpenOrchestrator/scheduler/connection_frame.py +0 -96
  45. openorchestrator-1.3.1.dist-info/METADATA +0 -60
  46. openorchestrator-1.3.1.dist-info/RECORD +0 -39
  47. {openorchestrator-1.3.1.dist-info → openorchestrator-2.0.0rc1.dist-info/licenses}/LICENSE +0 -0
  48. {openorchestrator-1.3.1.dist-info → openorchestrator-2.0.0rc1.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,372 @@
1
+ """This module contains tests of the functionality of db_util."""
2
+
3
+ import unittest
4
+ from datetime import datetime, timedelta
5
+ import time
6
+
7
+ from OpenOrchestrator.database import db_util
8
+ from OpenOrchestrator.database.logs import LogLevel
9
+ from OpenOrchestrator.database.queues import QueueStatus
10
+ from OpenOrchestrator.database.triggers import TriggerStatus
11
+
12
+ from OpenOrchestrator.tests import db_test_util
13
+
14
+
15
+ class TestDBUtil(unittest.TestCase):
16
+ """Test functionality of db_util."""
17
+ def setUp(self) -> None:
18
+ db_test_util.establish_clean_database()
19
+
20
+ def test_logs(self):
21
+ """Test creation of logs and retrieval by different filters."""
22
+ # Create some logs
23
+ creation_time = datetime.now() - timedelta(seconds=2)
24
+
25
+ for i in range(3):
26
+ db_util.create_log(f"Test {i}", LogLevel.TRACE, "Message")
27
+ db_util.create_log(f"Test {i}", LogLevel.INFO, "Message")
28
+ db_util.create_log(f"Test {i}", LogLevel.ERROR, "Message")
29
+
30
+ # Get all logs
31
+ logs = db_util.get_logs(0, 100)
32
+ self.assertEqual(len(logs), 9)
33
+
34
+ # Filter by level
35
+ logs = db_util.get_logs(0, 100, log_level=LogLevel.TRACE)
36
+ self.assertEqual(len(logs), 3)
37
+
38
+ # Get unique processes
39
+ process_names = db_util.get_unique_log_process_names()
40
+ self.assertEqual(len(process_names), 3)
41
+
42
+ # Filter by process
43
+ logs = db_util.get_logs(0, 100, process_name=process_names[0])
44
+ self.assertEqual(len(logs), 3)
45
+
46
+ # Filter by process and level
47
+ logs = db_util.get_logs(0, 100, log_level=LogLevel.INFO, process_name=process_names[1])
48
+ self.assertEqual(len(logs), 1)
49
+
50
+ # Filter by date
51
+ logs = db_util.get_logs(0, 100, from_date=creation_time)
52
+ self.assertEqual(len(logs), 9)
53
+
54
+ logs = db_util.get_logs(0, 100, to_date=creation_time)
55
+ self.assertEqual(len(logs), 0)
56
+
57
+ def test_constants(self):
58
+ """Test all things constants."""
59
+ # Create some constants
60
+ db_util.create_constant("Constant1", "Value1")
61
+ db_util.create_constant("Constant2", "Value2")
62
+
63
+ # Get all constants
64
+ constants = db_util.get_constants()
65
+ self.assertEqual(len(constants), 2)
66
+
67
+ # Get specific constant
68
+ constant = db_util.get_constant("Constant1")
69
+ self.assertEqual(constant.value, "Value1")
70
+ created_at = constant.changed_at
71
+ self.assertIsInstance(created_at, datetime)
72
+
73
+ # Update constant
74
+ time.sleep(0.1)
75
+ db_util.update_constant("Constant1", "New Value")
76
+ constant = db_util.get_constant("Constant1")
77
+ self.assertEqual(constant.value, "New Value")
78
+ self.assertGreater(constant.changed_at, created_at)
79
+
80
+ # Delete constant
81
+ db_util.delete_constant("Constant1")
82
+ with self.assertRaises(ValueError):
83
+ db_util.get_constant("Constant1")
84
+
85
+ def test_credentials(self):
86
+ """Test all things credentials."""
87
+ # Create some credentials
88
+ db_util.create_credential("Cred1", "User1", "Pass")
89
+ db_util.create_credential("Cred2", "User2", "Pass")
90
+
91
+ # Get all credentials
92
+ creds = db_util.get_credentials()
93
+ self.assertEqual(len(creds), 2)
94
+
95
+ # Check encryption salt
96
+ self.assertNotEqual(creds[0].password, creds[1].password)
97
+
98
+ # Get credential
99
+ cred = db_util.get_credential("Cred1")
100
+ self.assertEqual(cred.username, "User1")
101
+ self.assertEqual(cred.password, "Pass")
102
+ created_at = cred.changed_at
103
+ self.assertIsInstance(created_at, datetime)
104
+
105
+ # Update credential
106
+ time.sleep(0.1)
107
+ db_util.update_credential("Cred1", "New User", "New Pass")
108
+ cred = db_util.get_credential("Cred1")
109
+ self.assertEqual(cred.username, "New User")
110
+ self.assertEqual(cred.password, "New Pass")
111
+ self.assertGreater(cred.changed_at, created_at)
112
+
113
+ # Delete credential
114
+ db_util.delete_credential("Cred1")
115
+ with self.assertRaises(ValueError):
116
+ db_util.get_credential("Cred1")
117
+
118
+ def test_queue_elements(self):
119
+ """Test all things queue elements."""
120
+ # Create some queue elements
121
+ creation_time = datetime.now() - timedelta(seconds=2)
122
+
123
+ db_util.create_queue_element("Queue")
124
+ db_util.create_queue_element("Queue", reference="Ref", data="Data", created_by="Me")
125
+
126
+ # Bulk create queue elements
127
+ refs = tuple(f"Ref{i}" for i in range(10))
128
+ data = (None,) * 10
129
+ db_util.bulk_create_queue_elements("Bulk", references=refs, data=data)
130
+
131
+ with self.assertRaises(ValueError):
132
+ db_util.bulk_create_queue_elements("Bulk", ("Ref",), ())
133
+
134
+ # Get elements
135
+ elements = db_util.get_queue_elements("Queue")
136
+ self.assertEqual(len(elements), 2)
137
+
138
+ # Get next element
139
+ element = db_util.get_next_queue_element("Queue", set_status=False)
140
+ self.assertIsNotNone(element)
141
+ self.assertEqual(element.status, QueueStatus.NEW)
142
+
143
+ element = db_util.get_next_queue_element("Queue")
144
+ self.assertIsNotNone(element)
145
+ self.assertEqual(element.status, QueueStatus.IN_PROGRESS)
146
+
147
+ element2 = db_util.get_next_queue_element("Queue")
148
+ self.assertIsNotNone(element2)
149
+ self.assertNotEqual(element, element2)
150
+
151
+ # Update element
152
+ db_util.set_queue_element_status(element.id, QueueStatus.DONE, "Message")
153
+
154
+ # Filter elements
155
+ elements = db_util.get_queue_elements("Queue", reference="Ref")
156
+ self.assertEqual(len(elements), 1)
157
+
158
+ elements = db_util.get_queue_elements("Queue", status=QueueStatus.DONE)
159
+ self.assertEqual(len(elements), 1)
160
+
161
+ elements = db_util.get_queue_elements("Foo")
162
+ self.assertEqual(len(elements), 0)
163
+
164
+ elements = db_util.get_queue_elements("Queue", reference="Foo")
165
+ self.assertEqual(len(elements), 0)
166
+
167
+ # Filter by date
168
+ logs = db_util.get_queue_elements("Queue", from_date=creation_time)
169
+ self.assertEqual(len(logs), 2)
170
+
171
+ logs = db_util.get_queue_elements("Queue", to_date=creation_time)
172
+ self.assertEqual(len(logs), 0)
173
+
174
+ tomorrow = datetime.now() + timedelta(days=1)
175
+ logs = db_util.get_queue_elements("Queue", from_date=creation_time, to_date=tomorrow)
176
+ self.assertEqual(len(logs), 2)
177
+
178
+ # Delete element
179
+ db_util.delete_queue_element(element.id)
180
+ elements = db_util.get_queue_elements("Queue")
181
+ self.assertEqual(len(elements), 1)
182
+
183
+ # Queue count
184
+ count = db_util.get_queue_count()
185
+ self.assertEqual(count["Bulk"][QueueStatus.NEW], 10)
186
+
187
+ # Get element from empty queue
188
+ element = db_util.get_next_queue_element("Empty Queue")
189
+ self.assertIsNone(element)
190
+
191
+ def test_triggers(self):
192
+ """Test generic trigger functionality."""
193
+ db_test_util.reset_triggers()
194
+
195
+ # Get triggers
196
+ triggers = db_util.get_single_triggers()
197
+ self.assertEqual(len(triggers), 1)
198
+
199
+ triggers = db_util.get_scheduled_triggers()
200
+ self.assertEqual(len(triggers), 1)
201
+
202
+ triggers = db_util.get_queue_triggers()
203
+ self.assertEqual(len(triggers), 1)
204
+
205
+ triggers = db_util.get_all_triggers()
206
+ self.assertEqual(len(triggers), 3)
207
+
208
+ trigger = db_util.get_trigger(triggers[0].id)
209
+ self.assertIsNotNone(trigger)
210
+ self.assertIsNotNone(trigger.id)
211
+
212
+ # Update trigger
213
+ trigger.process_path = "New path"
214
+ db_util.update_trigger(trigger)
215
+ trigger = db_util.get_trigger(trigger.id)
216
+ self.assertEqual(trigger.process_path, "New path")
217
+
218
+ # Delete trigger
219
+ db_util.delete_trigger(trigger.id)
220
+ with self.assertRaises(ValueError):
221
+ db_util.get_trigger(trigger.id)
222
+
223
+ def test_single_triggers(self):
224
+ """Test running and updating single triggers."""
225
+ db_test_util.reset_triggers()
226
+
227
+ # Get next single trigger
228
+ trigger = db_util.get_pending_single_triggers()[0]
229
+ self.assertIsNotNone(trigger)
230
+
231
+ # Begin trigger
232
+ has_begun = db_util.begin_single_trigger(trigger.id)
233
+ self.assertTrue(has_begun)
234
+
235
+ # Begin already running trigger
236
+ has_begun = db_util.begin_single_trigger(trigger.id)
237
+ self.assertFalse(has_begun)
238
+
239
+ # Check is running- and next run
240
+ trigger = db_util.get_trigger(trigger.id)
241
+ self.assertEqual(trigger.process_status, TriggerStatus.RUNNING)
242
+ self.assertIsNotNone(trigger.last_run)
243
+
244
+ # No new trigger when the other is running
245
+ none_trigger = db_util.get_pending_single_triggers()
246
+ self.assertEqual(len(none_trigger), 0)
247
+
248
+ # Set status
249
+ db_util.set_trigger_status(trigger.id, TriggerStatus.DONE)
250
+ trigger = db_util.get_trigger(trigger.id)
251
+ self.assertEqual(trigger.process_status, TriggerStatus.DONE)
252
+
253
+ def test_scheduled_triggers(self):
254
+ """Test running and updating scheduled triggers."""
255
+ db_test_util.reset_triggers()
256
+
257
+ # Get next trigger
258
+ trigger = db_util.get_pending_scheduled_triggers()[0]
259
+ self.assertIsNotNone(trigger)
260
+
261
+ # Begin trigger
262
+ run_time = trigger.next_run
263
+ has_begun = db_util.begin_scheduled_trigger(trigger.id)
264
+ self.assertTrue(has_begun)
265
+
266
+ # Begin already running trigger
267
+ has_begun = db_util.begin_scheduled_trigger(trigger.id)
268
+ self.assertFalse(has_begun)
269
+
270
+ # Check is running- and next run
271
+ trigger = db_util.get_trigger(trigger.id)
272
+ self.assertGreater(trigger.next_run, run_time)
273
+ self.assertEqual(trigger.process_status, TriggerStatus.RUNNING)
274
+ self.assertIsNotNone(trigger.last_run)
275
+
276
+ # No new trigger when other is running
277
+ trigger_list = db_util.get_pending_scheduled_triggers()
278
+ self.assertEqual(len(trigger_list), 0)
279
+
280
+ def test_queue_triggers(self):
281
+ """Test running and updating queue triggers."""
282
+ db_test_util.reset_triggers()
283
+
284
+ # Test with empty queue
285
+ trigger_list = db_util.get_pending_queue_triggers()
286
+ self.assertEqual(len(trigger_list), 0)
287
+
288
+ # Test with 1 item in queue (triggers on 2)
289
+ db_util.create_queue_element("Trigger Queue")
290
+ trigger_list = db_util.get_pending_queue_triggers()
291
+ self.assertEqual(len(trigger_list), 0)
292
+
293
+ # Test with 2 items in queue
294
+ db_util.create_queue_element("Trigger Queue")
295
+ trigger = db_util.get_pending_queue_triggers()[0]
296
+ self.assertIsNotNone(trigger)
297
+
298
+ # Begin trigger
299
+ has_begun = db_util.begin_queue_trigger(trigger.id)
300
+ self.assertTrue(has_begun)
301
+
302
+ # Begin already running trigger
303
+ has_begun = db_util.begin_queue_trigger(trigger.id)
304
+ self.assertFalse(has_begun)
305
+
306
+ # Check is running
307
+ trigger = db_util.get_trigger(trigger.id)
308
+ self.assertEqual(trigger.process_status, TriggerStatus.RUNNING)
309
+ self.assertIsNotNone(trigger.last_run)
310
+
311
+ # No new trigger when other is running
312
+ trigger_list = db_util.get_pending_queue_triggers()
313
+ self.assertEqual(len(trigger_list), 0)
314
+
315
+ def test_log_truncation(self):
316
+ """Create logs with various lengths and test if their length is as expected"""
317
+ # Create some logs
318
+ long_message = "HelloWorld"*1000
319
+ medium_message = "a"*8000
320
+ short_message = "HelloWorld"
321
+
322
+ db_util.create_log("TruncateTest", LogLevel.TRACE, long_message)
323
+ db_util.create_log("TruncateTest", LogLevel.INFO, medium_message)
324
+ db_util.create_log("TruncateTest", LogLevel.ERROR, short_message)
325
+
326
+ # Test long message
327
+ logs = db_util.get_logs(0, 100, log_level=LogLevel.TRACE)
328
+ self.assertEqual(len(logs[0].log_message), 8000)
329
+
330
+ # Test medium message
331
+ logs = db_util.get_logs(0, 100, log_level=LogLevel.INFO)
332
+ self.assertEqual(len(logs[0].log_message), len(medium_message))
333
+
334
+ # Test short message
335
+ logs = db_util.get_logs(0, 100, log_level=LogLevel.ERROR)
336
+ self.assertEqual(len(logs[0].log_message), len(short_message))
337
+
338
+ def test_schedulers(self):
339
+ """Make pings from imitated machines and verify that they are registered."""
340
+
341
+ db_util.send_ping_from_scheduler("Machine1")
342
+
343
+ # Test one ping
344
+ schedulers = db_util.get_schedulers()
345
+ self.assertEqual(len(schedulers), 1)
346
+
347
+ # Test multiple pings
348
+ db_util.send_ping_from_scheduler("Machine2")
349
+ db_util.send_ping_from_scheduler("Machine3")
350
+ schedulers = db_util.get_schedulers()
351
+ self.assertEqual(len(schedulers), 3)
352
+
353
+ # Test that a ping from a machine that pinged earlier doesn't change the amount of schedulers
354
+ db_util.send_ping_from_scheduler("Machine1")
355
+ schedulers = db_util.get_schedulers()
356
+ self.assertEqual(len(schedulers), 3)
357
+
358
+ # Test types in Scheduler
359
+ test_scheduler = schedulers[0]
360
+ self.assertIsInstance(test_scheduler.machine_name, str)
361
+ self.assertIsInstance(test_scheduler.last_update, datetime)
362
+
363
+ # Test trigger
364
+ db_util.start_trigger_from_machine("Machine1", "Test Trigger")
365
+ schedulers = db_util.get_schedulers()
366
+ test_scheduler = schedulers[0]
367
+ self.assertIsInstance(test_scheduler.latest_trigger, str)
368
+ self.assertIsInstance(test_scheduler.latest_trigger_time, datetime)
369
+
370
+
371
+ if __name__ == '__main__':
372
+ unittest.main()
@@ -0,0 +1,142 @@
1
+ """This module contains tests for OrchestratorConnection."""
2
+
3
+ import unittest
4
+ from datetime import datetime
5
+ from uuid import UUID
6
+ import os
7
+
8
+ from OpenOrchestrator.orchestrator_connection.connection import OrchestratorConnection
9
+ from OpenOrchestrator.common import crypto_util
10
+ from OpenOrchestrator.database import db_util
11
+ from OpenOrchestrator.database.logs import LogLevel
12
+ from OpenOrchestrator.database.queues import QueueStatus
13
+
14
+ from OpenOrchestrator.tests import db_test_util
15
+
16
+
17
+ class TestOrchestratorConnection(unittest.TestCase):
18
+ """Tests for OrchestratorConnection."""
19
+ @classmethod
20
+ def setUpClass(cls) -> None:
21
+ db_test_util.establish_clean_database()
22
+ process_name = "Process"
23
+ cls.trigger_id = db_util.create_single_trigger(trigger_name=process_name,
24
+ process_name=process_name,
25
+ next_run=datetime.now(),
26
+ process_path="",
27
+ process_args="",
28
+ is_git_repo=False,
29
+ is_blocking=False,
30
+ priority=0,
31
+ scheduler_whitelist=""
32
+ )
33
+ cls.connection = OrchestratorConnection("Process", os.environ["CONN_STRING"], crypto_util.get_key(), "Args", cls.trigger_id)
34
+
35
+ def test_trigger_pause(self):
36
+ """Test pausing triggers."""
37
+ self.assertFalse(self.connection.is_trigger_pausing())
38
+ self.connection.pause_my_trigger()
39
+ self.assertTrue(self.connection.is_trigger_pausing())
40
+
41
+ def test_logging(self):
42
+ """Test all three logging functions."""
43
+ # Create some logs
44
+ self.connection.log_trace(LogLevel.TRACE.value)
45
+ self.connection.log_info(LogLevel.INFO.value)
46
+ self.connection.log_error(LogLevel.ERROR.value)
47
+
48
+ # Do the same test for each level
49
+ for level in LogLevel:
50
+ log = db_util.get_logs(0, 1, log_level=level)[0]
51
+ self.assertIsNotNone(log)
52
+
53
+ self.assertIsInstance(log.id, UUID)
54
+ self.assertEqual(log.log_level, level)
55
+ self.assertEqual(log.log_message, level.value)
56
+ self.assertIsInstance(log.log_time, datetime)
57
+ self.assertEqual(log.process_name, "Process")
58
+
59
+ logs = db_util.get_logs(0, 100)
60
+ self.assertEqual(len(logs), 3)
61
+
62
+ def test_constants(self):
63
+ """Test all things constants."""
64
+ # Create a constant
65
+ db_util.create_constant("Constant", "Value")
66
+
67
+ # Get constant
68
+ constant = self.connection.get_constant("Constant")
69
+ self.assertIsNotNone(constant)
70
+ self.assertEqual(constant.name, "Constant")
71
+ self.assertEqual(constant.value, "Value")
72
+ self.assertIsInstance(constant.changed_at, datetime)
73
+
74
+ # Update constant
75
+ self.connection.update_constant("Constant", "New Value")
76
+ constant = self.connection.get_constant("Constant")
77
+ self.assertEqual(constant.value, "New Value")
78
+
79
+ def test_credentials(self):
80
+ """Test all things credentials."""
81
+ # Create credential
82
+ db_util.create_credential("Credential", "Username", "Password")
83
+
84
+ # Get credential
85
+ credential = self.connection.get_credential("Credential")
86
+ self.assertIsNotNone(credential)
87
+ self.assertEqual(credential.name, "Credential")
88
+ self.assertEqual(credential.username, "Username")
89
+ self.assertEqual(credential.password, "Password")
90
+ self.assertIsInstance(credential.changed_at, datetime)
91
+
92
+ # Update credential
93
+ self.connection.update_credential("Credential", "New Username", "New Password")
94
+ credential = self.connection.get_credential("Credential")
95
+ self.assertEqual(credential.username, "New Username")
96
+ self.assertEqual(credential.password, "New Password")
97
+
98
+ def test_queue_elements(self):
99
+ """Test all things queue elements."""
100
+ # Create elements
101
+ self.connection.create_queue_element("Queue")
102
+ self.connection.create_queue_element("Queue", reference="Ref", data="data", created_by="Me")
103
+
104
+ self.connection.bulk_create_queue_elements(
105
+ "Bulk Queue",
106
+ references=(None,)*10,
107
+ data=("data",)*10,
108
+ created_by="Me"
109
+ )
110
+
111
+ # Get elements
112
+ elements = self.connection.get_queue_elements("Queue")
113
+ self.assertEqual(len(elements), 2)
114
+
115
+ elements = self.connection.get_queue_elements("Queue", "Ref")
116
+ self.assertEqual(len(elements), 1)
117
+
118
+ # Get next
119
+ element = self.connection.get_next_queue_element("Bulk Queue", set_status=False)
120
+ self.assertIsNotNone(element)
121
+ self.assertEqual(element.status, QueueStatus.NEW)
122
+
123
+ element = self.connection.get_next_queue_element("Bulk Queue")
124
+ self.assertIsNotNone(element)
125
+ self.assertEqual(element.status, QueueStatus.IN_PROGRESS)
126
+
127
+ element2 = self.connection.get_next_queue_element("Bulk Queue")
128
+ self.assertNotEqual(element, element2)
129
+
130
+ # Set status
131
+ self.connection.set_queue_element_status(element.id, QueueStatus.DONE)
132
+ elements = self.connection.get_queue_elements("Bulk Queue", status=QueueStatus.DONE)
133
+ self.assertEqual(len(elements), 1)
134
+
135
+ # Delete element
136
+ self.connection.delete_queue_element(element.id)
137
+ elements = self.connection.get_queue_elements("Bulk Queue")
138
+ self.assertEqual(len(elements), 9)
139
+
140
+
141
+ if __name__ == '__main__':
142
+ unittest.main()
@@ -0,0 +1,143 @@
1
+ """This module contains tests for the trigger polling part of the Scheduler."""
2
+
3
+ import unittest
4
+ from unittest.mock import MagicMock, patch
5
+ from datetime import datetime
6
+
7
+ from OpenOrchestrator.scheduler import runner
8
+ from OpenOrchestrator.database import db_util
9
+ from OpenOrchestrator.database.triggers import SingleTrigger
10
+ from OpenOrchestrator.tests import db_test_util
11
+
12
+
13
+ @patch("OpenOrchestrator.scheduler.util.get_scheduler_name", return_value="Machine")
14
+ class TestTriggerPolling(unittest.TestCase):
15
+ """Test the trigger polling functionality of the Scheduler."""
16
+ def setUp(self) -> None:
17
+ db_test_util.establish_clean_database()
18
+
19
+ def test_poll_triggers_single(self, *_):
20
+ """Test polling single triggers."""
21
+ mock_app = setup_mock_app(has_running_jobs=False, is_exclusive=False)
22
+
23
+ # Test with no triggers
24
+ trigger = runner.poll_triggers(mock_app)
25
+ self.assertIsNone(trigger)
26
+
27
+ # Test with idle trigger
28
+ db_util.create_single_trigger("Future single trigger", "", datetime(2100, 1, 1), "", "", False, False, 0, [])
29
+ trigger = runner.poll_triggers(mock_app)
30
+ self.assertIsNone(trigger)
31
+
32
+ # Test with overdue trigger
33
+ db_util.create_single_trigger("Past single trigger", "", datetime(2020, 1, 1), "", "", False, False, 0, [])
34
+ trigger = runner.poll_triggers(mock_app)
35
+ self.assertIsInstance(trigger, SingleTrigger)
36
+ self.assertEqual(trigger.trigger_name, "Past single trigger")
37
+
38
+ def test_poll_triggers_priority(self, *_):
39
+ """Test polling triggers with priorities set."""
40
+ mock_app = setup_mock_app(has_running_jobs=False, is_exclusive=False)
41
+
42
+ db_util.create_single_trigger("Low", "", datetime(2000, 1, 1), "", "", False, False, 0, [])
43
+ db_util.create_single_trigger("High", "", datetime(2000, 1, 1), "", "", False, False, 100, [])
44
+
45
+ trigger = runner.poll_triggers(mock_app)
46
+ self.assertEqual(trigger.trigger_name, "High")
47
+
48
+ db_util.create_single_trigger("Higher Future", "", datetime(2100, 1, 1), "", "", False, False, 200, [])
49
+
50
+ trigger = runner.poll_triggers(mock_app)
51
+ self.assertEqual(trigger.trigger_name, "High")
52
+
53
+ def test_poll_triggers_mixed(self, *_):
54
+ """Test mixed trigger types with priorities set.
55
+ Equal priorities should be prioritied by trigger type:
56
+ Single > Scheduled > Queue
57
+ """
58
+ mock_app = setup_mock_app(has_running_jobs=False, is_exclusive=False)
59
+
60
+ db_util.create_queue_trigger("Queue", "", "Queue", "", "", False, False, 1, 0, [])
61
+ db_util.create_queue_element("Queue")
62
+ trigger = runner.poll_triggers(mock_app)
63
+ self.assertEqual(trigger.trigger_name, "Queue")
64
+
65
+ db_util.create_scheduled_trigger("Scheduled", "", "", datetime(2000, 1, 1), "", "", False, False, 0, [])
66
+ trigger = runner.poll_triggers(mock_app)
67
+ self.assertEqual(trigger.trigger_name, "Scheduled")
68
+
69
+ db_util.create_single_trigger("Single", "", datetime(2000, 1, 1), "", "", False, False, 0, [])
70
+ trigger = runner.poll_triggers(mock_app)
71
+ self.assertEqual(trigger.trigger_name, "Single")
72
+
73
+ db_util.create_queue_trigger("Queue High", "", "Queue", "", "", False, False, 1, 1, [])
74
+ trigger = runner.poll_triggers(mock_app)
75
+ self.assertEqual(trigger.trigger_name, "Queue High")
76
+
77
+ db_util.create_scheduled_trigger("Scheduled High", "", "", datetime(2000, 1, 1), "", "", False, False, 1, [])
78
+ trigger = runner.poll_triggers(mock_app)
79
+ self.assertEqual(trigger.trigger_name, "Scheduled High")
80
+
81
+ db_util.create_single_trigger("Single High", "", datetime(2000, 1, 1), "", "", False, False, 1, [])
82
+ trigger = runner.poll_triggers(mock_app)
83
+ self.assertEqual(trigger.trigger_name, "Single High")
84
+
85
+ def test_poll_triggers_blocking(self, *_):
86
+ """Test polling triggers when other jobs are running."""
87
+ mock_app = setup_mock_app(has_running_jobs=True, is_exclusive=False)
88
+
89
+ db_util.create_single_trigger("Single Blocking", "", datetime(2000, 1, 1), "", "", False, True, 0, [])
90
+ trigger = runner.poll_triggers(mock_app)
91
+ self.assertIsNone(trigger)
92
+
93
+ db_util.create_single_trigger("Single Non-blocking", "", datetime(2000, 1, 1), "", "", False, False, 0, [])
94
+ trigger = runner.poll_triggers(mock_app)
95
+ self.assertEqual(trigger.trigger_name, "Single Non-blocking")
96
+
97
+ def test_poll_triggers_whitelist_non_exclusive(self, *_):
98
+ """Test polling whitelisted triggers when Scheduler is not exclusive."""
99
+ mock_app = setup_mock_app(has_running_jobs=False, is_exclusive=False)
100
+
101
+ db_util.create_single_trigger("Single non machine", "", datetime(2000, 1, 1), "", "", False, False, 0, ["Non machine"])
102
+ trigger = runner.poll_triggers(mock_app)
103
+ self.assertIsNone(trigger)
104
+
105
+ db_util.create_single_trigger("Single no whitelist", "", datetime(2000, 1, 1), "", "", False, False, 0, [])
106
+ trigger = runner.poll_triggers(mock_app)
107
+ self.assertEqual(trigger.trigger_name, "Single no whitelist")
108
+
109
+ def test_poll_triggers_whitelist_exclusive(self, *_):
110
+ """Test polling whitelisted triggers when Scheduler is exclusive."""
111
+ mock_app = setup_mock_app(has_running_jobs=False, is_exclusive=True)
112
+
113
+ db_util.create_single_trigger("Single non machine", "", datetime(2000, 1, 1), "", "", False, False, 0, ["Non machine"])
114
+ trigger = runner.poll_triggers(mock_app)
115
+ self.assertIsNone(trigger)
116
+
117
+ db_util.create_single_trigger("Single no whitelist", "", datetime(2000, 1, 1), "", "", False, False, 0, [])
118
+ trigger = runner.poll_triggers(mock_app)
119
+ self.assertIsNone(trigger)
120
+
121
+ db_util.create_single_trigger("Single whitelist", "", datetime(2000, 1, 1), "", "", False, False, 0, ["Machine"])
122
+ trigger = runner.poll_triggers(mock_app)
123
+ self.assertEqual(trigger.trigger_name, "Single whitelist")
124
+
125
+
126
+ def setup_mock_app(*, has_running_jobs: bool, is_exclusive: bool) -> MagicMock:
127
+ """Create a mock Application object to be used in tests.
128
+
129
+ Args:
130
+ has_running_jobs: If the app should simulate having running jobs.
131
+ is_exclusive: If the app should simulate only running whitelisted triggers.
132
+
133
+ Returns:
134
+ A mock Application object.
135
+ """
136
+ mock_app = MagicMock()
137
+ mock_app.running_jobs = [None] if has_running_jobs else []
138
+ mock_app.settings_tab_.whitelist_value.get.return_value = is_exclusive
139
+ return mock_app
140
+
141
+
142
+ if __name__ == '__main__':
143
+ unittest.main()
File without changes