From 9aaf694acf8777cd4ef415fc33d8d3a4c41e076a Mon Sep 17 00:00:00 2001 From: Chris Meyers Date: Thu, 10 Nov 2016 11:02:12 -0500 Subject: [PATCH] always allow running at least 1 job * Regardless of capacity * Add unit tests around this logic --- awx/main/scheduler/__init__.py | 3 +- awx/main/tests/unit/scheduler/conftest.py | 8 +++--- .../unit/scheduler/test_scheduler_job.py | 28 +++++++++++++++++++ 3 files changed, 34 insertions(+), 5 deletions(-) diff --git a/awx/main/scheduler/__init__.py b/awx/main/scheduler/__init__.py index 060c2d0bce..16ca577d6c 100644 --- a/awx/main/scheduler/__init__.py +++ b/awx/main/scheduler/__init__.py @@ -243,7 +243,6 @@ class TaskManager(): for inventory_source_task in self.graph.get_inventory_sources(task['inventory_id']): if inventory_source_task['id'] in inventory_sources_already_updated: - print("Inventory already updated") continue if self.graph.should_update_related_inventory_source(task, inventory_source_task['id']): inventory_task = self.create_inventory_update(task, inventory_source_task) @@ -316,6 +315,8 @@ class TaskManager(): self.capacity_used += t.task_impact() def would_exceed_capacity(self, task): + if self.capacity_used == 0: + return False return (task.task_impact() + self.capacity_used > self.capacity_total) def consume_capacity(self, task): diff --git a/awx/main/tests/unit/scheduler/conftest.py b/awx/main/tests/unit/scheduler/conftest.py index 97eec0dbb4..42f2b59cd3 100644 --- a/awx/main/tests/unit/scheduler/conftest.py +++ b/awx/main/tests/unit/scheduler/conftest.py @@ -22,7 +22,7 @@ def epoch(): @pytest.fixture def scheduler_factory(mocker, epoch): - mocker.patch('awx.main.models.Instance.objects.total_capacity', return_value=999999999) + mocker.patch('awx.main.models.Instance.objects.total_capacity', return_value=10000) def fn(tasks=[], inventory_sources=[], latest_project_updates=[], latest_inventory_updates=[], create_project_update=None, create_inventory_update=None): sched = TaskManager() @@ -190,15 +190,15 @@ Job ''' @pytest.fixture def job_factory(epoch): - def fn(project__scm_update_on_launch=True, inventory__inventory_sources=[]): + def fn(id=1, project__scm_update_on_launch=True, inventory__inventory_sources=[], allow_simultaneous=False): return JobDict({ - 'id': 1, + 'id': id, 'status': 'pending', 'job_template_id': 1, 'project_id': 1, 'inventory_id': 1, 'launch_type': 'manual', - 'allow_simultaneous': False, + 'allow_simultaneous': allow_simultaneous, 'created': epoch - timedelta(seconds=99), 'celery_task_id': '', 'project__scm_update_on_launch': project__scm_update_on_launch, diff --git a/awx/main/tests/unit/scheduler/test_scheduler_job.py b/awx/main/tests/unit/scheduler/test_scheduler_job.py index 735ce04d95..5d045efaec 100644 --- a/awx/main/tests/unit/scheduler/test_scheduler_job.py +++ b/awx/main/tests/unit/scheduler/test_scheduler_job.py @@ -54,3 +54,31 @@ class TestJob(): scheduler.start_task.assert_called_with(pending_job) +class TestCapacity(): + @pytest.fixture + def pending_job_high_impact(self, mocker, job_factory): + pending_job = job_factory(project__scm_update_on_launch=False) + mocker.patch.object(pending_job, 'task_impact', return_value=10001) + return pending_job + + def test_no_capacity(self, scheduler_factory, pending_job_high_impact): + scheduler = scheduler_factory(tasks=[pending_job_high_impact]) + + scheduler._schedule() + + scheduler.start_task.assert_called_with(pending_job_high_impact) + + @pytest.fixture + def pending_jobs_impactful(self, mocker, job_factory): + pending_jobs = [job_factory(id=i + 1, project__scm_update_on_launch=False, allow_simultaneous=True) for i in xrange(0, 3)] + map(lambda pending_job: mocker.patch.object(pending_job, 'task_impact', return_value=10), pending_jobs) + return pending_jobs + + def test_capacity_exhausted(self, mocker, scheduler_factory, pending_jobs_impactful): + scheduler = scheduler_factory(tasks=pending_jobs_impactful) + + scheduler._schedule() + + calls = [mocker.call(job) for job in pending_jobs_impactful] + scheduler.start_task.assert_has_calls(calls) +