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.
- OpenOrchestrator/__main__.py +66 -12
- OpenOrchestrator/common/connection_frame.py +10 -4
- OpenOrchestrator/database/base.py +8 -0
- OpenOrchestrator/database/constants.py +3 -15
- OpenOrchestrator/database/db_util.py +110 -37
- OpenOrchestrator/database/logs.py +3 -15
- OpenOrchestrator/database/queues.py +3 -15
- OpenOrchestrator/database/schedulers.py +32 -0
- OpenOrchestrator/database/triggers.py +7 -16
- OpenOrchestrator/orchestrator/application.py +13 -8
- OpenOrchestrator/orchestrator/datetime_input.py +2 -2
- OpenOrchestrator/orchestrator/popups/constant_popup.py +8 -6
- OpenOrchestrator/orchestrator/popups/credential_popup.py +10 -8
- OpenOrchestrator/orchestrator/popups/generic_popups.py +15 -2
- OpenOrchestrator/orchestrator/popups/trigger_popup.py +25 -14
- OpenOrchestrator/orchestrator/tabs/constants_tab.py +5 -2
- OpenOrchestrator/orchestrator/tabs/logging_tab.py +3 -0
- OpenOrchestrator/orchestrator/tabs/queue_tab.py +4 -1
- OpenOrchestrator/orchestrator/tabs/schedulers_tab.py +45 -0
- OpenOrchestrator/orchestrator/tabs/settings_tab.py +2 -5
- OpenOrchestrator/orchestrator/tabs/trigger_tab.py +9 -5
- OpenOrchestrator/orchestrator/test_helper.py +17 -0
- OpenOrchestrator/orchestrator_connection/connection.py +21 -4
- OpenOrchestrator/scheduler/application.py +3 -2
- OpenOrchestrator/scheduler/run_tab.py +16 -6
- OpenOrchestrator/scheduler/runner.py +51 -63
- OpenOrchestrator/scheduler/settings_tab.py +90 -14
- OpenOrchestrator/scheduler/util.py +8 -0
- OpenOrchestrator/tests/__init__.py +0 -0
- OpenOrchestrator/tests/db_test_util.py +40 -0
- OpenOrchestrator/tests/test_db_util.py +372 -0
- OpenOrchestrator/tests/test_orchestrator_connection.py +142 -0
- OpenOrchestrator/tests/test_trigger_polling.py +143 -0
- OpenOrchestrator/tests/ui_tests/__init__.py +0 -0
- OpenOrchestrator/tests/ui_tests/test_constants_tab.py +167 -0
- OpenOrchestrator/tests/ui_tests/test_logging_tab.py +180 -0
- OpenOrchestrator/tests/ui_tests/test_queues_tab.py +126 -0
- OpenOrchestrator/tests/ui_tests/test_schedulers_tab.py +47 -0
- OpenOrchestrator/tests/ui_tests/test_trigger_tab.py +243 -0
- OpenOrchestrator/tests/ui_tests/ui_util.py +151 -0
- openorchestrator-2.0.0rc1.dist-info/METADATA +158 -0
- openorchestrator-2.0.0rc1.dist-info/RECORD +55 -0
- {openorchestrator-1.3.1.dist-info → openorchestrator-2.0.0rc1.dist-info}/WHEEL +1 -1
- OpenOrchestrator/scheduler/connection_frame.py +0 -96
- openorchestrator-1.3.1.dist-info/METADATA +0 -60
- openorchestrator-1.3.1.dist-info/RECORD +0 -39
- {openorchestrator-1.3.1.dist-info → openorchestrator-2.0.0rc1.dist-info/licenses}/LICENSE +0 -0
- {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
|