| |
@@ -7,13 +7,16 @@
|
| |
import logging
|
| |
import subprocess
|
| |
from unittest.mock import MagicMock, patch
|
| |
- from munch import Munch
|
| |
|
| |
- WORKDIR = os.path.dirname(__file__)
|
| |
+ import pytest
|
| |
+ from munch import Munch
|
| |
+ from copr_common.enums import DefaultActionPriorityEnum
|
| |
|
| |
from copr_backend.helpers import get_redis_connection
|
| |
- from copr_backend.actions import ActionWorkerManager, ActionQueueTask
|
| |
- from copr_backend.worker_manager import JobQueue
|
| |
+ from copr_backend.actions import ActionWorkerManager, ActionQueueTask, Action
|
| |
+ from copr_backend.worker_manager import JobQueue, WorkerManager, QueueTask
|
| |
+
|
| |
+ WORKDIR = os.path.dirname(__file__)
|
| |
|
| |
REDIS_OPTS = Munch(
|
| |
redis_db=9,
|
| |
@@ -24,7 +27,8 @@
|
| |
log.setLevel(logging.DEBUG)
|
| |
|
| |
|
| |
- class ToyWorkerManager(ActionWorkerManager):
|
| |
+ class ToyWorkerManager(WorkerManager):
|
| |
+ # pylint: disable=abstract-method
|
| |
process_counter = 0
|
| |
task_sleep = 0
|
| |
|
| |
@@ -48,6 +52,19 @@
|
| |
subprocess.check_call(list(map(str, cmd)), env=environ)
|
| |
|
| |
|
| |
+ class ToyActionWorkerManager(ToyWorkerManager, ActionWorkerManager):
|
| |
+ pass
|
| |
+
|
| |
+
|
| |
+ class ToyQueueTask(QueueTask):
|
| |
+ def __init__(self, _id):
|
| |
+ self._id = _id
|
| |
+
|
| |
+ @property
|
| |
+ def id(self):
|
| |
+ return self._id
|
| |
+
|
| |
+
|
| |
class TestPrioQueue(object):
|
| |
def setup_method(self, method):
|
| |
raw_actions = [0, 1, 2, 3, 3, 3, 4, 5, 6, 7, 8, 9]
|
| |
@@ -87,30 +104,28 @@
|
| |
assert self.get_tasks() == [6, 7, 9, 0, 1, 2, 3, 4, 5, 8]
|
| |
|
| |
|
| |
- class TestWorkerManager(object):
|
| |
+ class BaseTestWorkerManager:
|
| |
redis = None
|
| |
worker_manager = None
|
| |
|
| |
def setup_method(self, method):
|
| |
+ self.setup_redis()
|
| |
+ self.setup_worker_manager()
|
| |
+ self.setup_tasks()
|
| |
+
|
| |
+ def setup_redis(self):
|
| |
self.redis = get_redis_connection(REDIS_OPTS)
|
| |
self.redis.flushall()
|
| |
|
| |
+ def setup_worker_manager(self):
|
| |
self.worker_manager = ToyWorkerManager(
|
| |
redis_connection=self.redis,
|
| |
max_workers=5,
|
| |
log=log)
|
| |
|
| |
- prefix = 'toy:' + str(time.time())
|
| |
- self.worker_manager.worker_prefix = prefix
|
| |
- prefix += ':'
|
| |
- self.wprefix = prefix
|
| |
- self.w0 = prefix + '0'
|
| |
- self.w1 = prefix + '1'
|
| |
-
|
| |
- self.worker_manager.frontend_client = MagicMock()
|
| |
-
|
| |
+ def setup_tasks(self):
|
| |
raw_actions = [0, 1, 2, 3, 3, 3, 4, 5, 6, 7, 8, 9]
|
| |
- actions = [ActionQueueTask(action) for action in raw_actions]
|
| |
+ actions = [ToyQueueTask(action) for action in raw_actions]
|
| |
for action in actions:
|
| |
self.worker_manager.add_task(action)
|
| |
|
| |
@@ -127,6 +142,8 @@
|
| |
break
|
| |
return count
|
| |
|
| |
+
|
| |
+ class TestWorkerManager(BaseTestWorkerManager):
|
| |
def test_worker_starts(self):
|
| |
task = self.worker_manager.tasks.pop_task()
|
| |
assert task.id == 0
|
| |
@@ -137,6 +154,29 @@
|
| |
def test_number_of_tasks(self):
|
| |
assert self.remaining_tasks() == 10
|
| |
|
| |
+
|
| |
+ class TestActionWorkerManager(BaseTestWorkerManager):
|
| |
+ # pylint: disable=attribute-defined-outside-init
|
| |
+ def setup_worker_manager(self):
|
| |
+ self.worker_manager = ToyActionWorkerManager(
|
| |
+ redis_connection=self.redis,
|
| |
+ max_workers=5,
|
| |
+ log=log)
|
| |
+
|
| |
+ prefix = 'toy:' + str(time.time())
|
| |
+ self.worker_manager.worker_prefix = prefix
|
| |
+ prefix += ':'
|
| |
+ self.wprefix = prefix
|
| |
+ self.w0 = prefix + '0'
|
| |
+ self.w1 = prefix + '1'
|
| |
+ self.worker_manager.frontend_client = MagicMock()
|
| |
+
|
| |
+ def setup_tasks(self):
|
| |
+ raw_actions = [0, 1, 2, 3, 3, 3, 4, 5, 6, 7, 8, 9]
|
| |
+ for action in raw_actions:
|
| |
+ action = ToyQueueTask(action)
|
| |
+ self.worker_manager.add_task(action)
|
| |
+
|
| |
def test_run_starts_the_workers(self):
|
| |
self.worker_manager.run(timeout=0.0001)
|
| |
workers = self.workers()
|
| |
@@ -211,7 +251,7 @@
|
| |
self.worker_manager.run(timeout=0.0001)
|
| |
|
| |
queue = copy.deepcopy(self.worker_manager.tasks)
|
| |
- self.worker_manager.add_task(ActionQueueTask(0))
|
| |
+ self.worker_manager.add_task(ToyQueueTask(0))
|
| |
assert len(queue.prio_queue) == len(self.worker_manager.tasks.prio_queue)
|
| |
assert ('root', logging.WARNING, "Task 0 has worker, skipped") in caplog.record_tuples
|
| |
|
| |
@@ -222,7 +262,7 @@
|
| |
|
| |
# only one task, but it will take some time.
|
| |
self.worker_manager.task_sleep = 0.5
|
| |
- self.worker_manager.add_task(ActionQueueTask(0))
|
| |
+ self.worker_manager.add_task(ToyQueueTask(0))
|
| |
|
| |
# start the worker
|
| |
self.worker_manager.run(timeout=0.0001) # start them task
|
| |
@@ -250,7 +290,7 @@
|
| |
"""
|
| |
self.worker_manager.task_sleep = 3 # assure task takes some time
|
| |
self.worker_manager.clean_tasks()
|
| |
- self.worker_manager.add_task(ActionQueueTask(0))
|
| |
+ self.worker_manager.add_task(ToyQueueTask(0))
|
| |
self.worker_manager.worker_timeout_start = 1
|
| |
self.worker_manager.worker_timeout_deadcheck = 1.5
|
| |
|
| |
@@ -283,3 +323,87 @@
|
| |
self.worker_manager.run(timeout=0.0001)
|
| |
|
| |
assert len(self.worker_manager.worker_ids()) == 0
|
| |
+
|
| |
+
|
| |
+ class TestActionWorkerManagerPriorities(BaseTestWorkerManager):
|
| |
+ def setup_worker_manager(self):
|
| |
+ self.worker_manager = ToyActionWorkerManager(
|
| |
+ redis_connection=self.redis,
|
| |
+ max_workers=5,
|
| |
+ log=log)
|
| |
+
|
| |
+ def setup_tasks(self):
|
| |
+ pass
|
| |
+
|
| |
+ def pop(self):
|
| |
+ return self.worker_manager.tasks.pop_task()
|
| |
+
|
| |
+ def test_actions_priorities(self):
|
| |
+ frontend_data = [
|
| |
+ {"id": 10, "priority": DefaultActionPriorityEnum("delete")},
|
| |
+ {"id": 11, "priority": DefaultActionPriorityEnum("delete")},
|
| |
+ {"id": 12, "priority": DefaultActionPriorityEnum("createrepo")},
|
| |
+ {"id": 13, "priority": DefaultActionPriorityEnum("update_comps")},
|
| |
+ {"id": 14, "priority": DefaultActionPriorityEnum("rawhide_to_release")},
|
| |
+ {"id": 15, "priority": DefaultActionPriorityEnum("rawhide_to_release")},
|
| |
+ {"id": 16, "priority": DefaultActionPriorityEnum("build_module")},
|
| |
+ {"id": 17, "priority": DefaultActionPriorityEnum("cancel_build")},
|
| |
+ {"id": 18, "priority": DefaultActionPriorityEnum("fork")},
|
| |
+ {"id": 19, "priority": DefaultActionPriorityEnum("gen_gpg_key")},
|
| |
+ {"id": 20, "priority": 0},
|
| |
+ ]
|
| |
+ for action in frontend_data:
|
| |
+ queue_task = ActionQueueTask(Action(MagicMock(), action, log=log))
|
| |
+ self.worker_manager.add_task(queue_task)
|
| |
+
|
| |
+ assert self.pop().id == 19
|
| |
+ assert self.pop().id == 17
|
| |
+
|
| |
+ # These have the same priority and the queue is FIFO
|
| |
+ assert self.pop().id == 12
|
| |
+ assert self.pop().id == 13
|
| |
+ assert self.pop().id == 16
|
| |
+ assert self.pop().id == 18
|
| |
+ assert self.pop().id == 20
|
| |
+
|
| |
+ assert self.pop().id == 10
|
| |
+ assert self.pop().id == 11
|
| |
+
|
| |
+ assert self.pop().id == 14
|
| |
+ assert self.pop().id == 15
|
| |
+
|
| |
+ # Tasks queue is empty now
|
| |
+ with pytest.raises(KeyError) as ex:
|
| |
+ self.pop()
|
| |
+ assert "empty" in str(ex)
|
| |
+
|
| |
+ def test_backend_priority_adjustments(self):
|
| |
+ """
|
| |
+ Test that backend still can adjust or ultimately override priorities
|
| |
+ """
|
| |
+ frontend_data = [
|
| |
+ {"id": 10, "priority": DefaultActionPriorityEnum("delete")},
|
| |
+ {"id": 11, "priority": DefaultActionPriorityEnum("delete")},
|
| |
+ {"id": 12, "priority": DefaultActionPriorityEnum("createrepo")},
|
| |
+ {"id": 13, "priority": DefaultActionPriorityEnum("gen_gpg_key")},
|
| |
+ {"id": 14, "priority": DefaultActionPriorityEnum("fork")},
|
| |
+ ]
|
| |
+ actions = [ActionQueueTask(Action(MagicMock(), action, log)) for action in frontend_data]
|
| |
+
|
| |
+ # QueueTask.backend_priority is a property which should be
|
| |
+ # overriden when in the class descendants.
|
| |
+ delattr(QueueTask, "backend_priority")
|
| |
+ actions[0].backend_priority = 0
|
| |
+ actions[1].backend_priority = -999
|
| |
+ actions[2].backend_priority = 999
|
| |
+ actions[3].backend_priority = 0
|
| |
+ actions[4].backend_priority = -900
|
| |
+
|
| |
+ for action in actions:
|
| |
+ self.worker_manager.add_task(action)
|
| |
+
|
| |
+ assert self.pop().id == 11
|
| |
+ assert self.pop().id == 14
|
| |
+ assert self.pop().id == 13
|
| |
+ assert self.pop().id == 10
|
| |
+ assert self.pop().id == 12
|
| |
This PR is still WIP