diff --git a/.zuul.d/zuul.yaml b/.zuul.d/zuul.yaml index 82d48483..c215c707 100644 --- a/.zuul.d/zuul.yaml +++ b/.zuul.d/zuul.yaml @@ -14,11 +14,14 @@ - rally-task-simple-job - rally-task-barbican: files: + - .zuul.d/zuul.yaml - rally-jobs/barbican.yaml - rally_openstack/common/osclients.py - rally_openstack/common/services/key_manager - rally_openstack/task/cleanup/resources.py - rally_openstack/task/scenarios/barbican + - tests/ci/playbooks + - tests/ci/osresources.py - rally-task-cinder # NOTE(andreykurilin): this requires more thing to configure before # launching. @@ -30,11 +33,14 @@ - rally-task-magnum: voting: false files: + - .zuul.d/zuul.yaml - rally-jobs/magnum.yaml - - rally_openstack/cleanup/resources.py - - rally_openstack/contexts/magnum - - rally_openstack/scenarios/magnum - - rally_openstack/osclients.py + - rally_openstack/common/osclients.py + - rally_openstack/task/cleanup/resources.py + - rally_openstack/task/contexts/magnum + - rally_openstack/task/scenarios/magnum + - tests/ci/playbooks + - tests/ci/osresources.py - rally-task-manila-no-ss: voting: false - rally-task-manila-ss: @@ -47,9 +53,13 @@ - rally-task-neutron - rally-task-neutron-trunk: files: + - .zuul.d/zuul.yaml - rally-jobs/neutron-trunk.yaml - - rally_openstack/scenarios/neutron/trunk.py - - rally_openstack/scenarios/neutron/network.py + - rally_openstack/common/osclients.py + - rally_openstack/task/scenarios/neutron/trunk.py + - rally_openstack/task/scenarios/neutron/network.py + - tests/ci/playbooks + - tests/ci/osresources.py - rally-task-neutron-with-extensions: voting: false - rally-task-nova: @@ -74,12 +84,30 @@ - rally-dsvm-tox-functional - rally-docker-check - rally-task-simple-job + - rally-task-barbican: + files: + - .zuul.d/zuul.yaml + - rally-jobs/barbican.yaml + - rally_openstack/common/osclients.py + - rally_openstack/common/services/key_manager + - rally_openstack/task/cleanup/resources.py + - rally_openstack/task/scenarios/barbican + - tests/ci/playbooks + - tests/ci/osresources.py - rally-task-cinder #- rally-task-heat - rally-task-ironic - rally-task-keystone-glance-swift - rally-task-mistral - rally-task-neutron + - rally-task-neutron-trunk: + files: + - rally-jobs/neutron-trunk.yaml + - rally_openstack/common/osclients.py + - rally_openstack/task/scenarios/neutron/trunk.py + - rally_openstack/task/scenarios/neutron/network.py + - tests/ci/playbooks + - tests/ci/osresources.py - rally-task-telemetry - rally-task-zaqar - rally-verify-tempest diff --git a/tests/unit/rally_jobs/test_zuul_jobs.py b/tests/unit/rally_jobs/test_zuul_jobs.py index 174e6369..2f6173d0 100644 --- a/tests/unit/rally_jobs/test_zuul_jobs.py +++ b/tests/unit/rally_jobs/test_zuul_jobs.py @@ -13,6 +13,7 @@ # under the License. import os +import re import yaml @@ -21,8 +22,8 @@ from tests.unit import test class RallyJobsTestCase(test.TestCase): - zuul_jobs_path = os.path.join( - os.path.dirname(rally_openstack.__file__), "..", ".zuul.d") + root_dir = os.path.dirname(os.path.dirname(rally_openstack.__file__)) + zuul_jobs_path = os.path.join(root_dir, ".zuul.d") def setUp(self): super(RallyJobsTestCase, self).setUp() @@ -34,35 +35,34 @@ class RallyJobsTestCase(test.TestCase): if "project" in item: self.project_cfg = item["project"] break + if self.project_cfg is None: + self.fail("Cannot detect project section from zuul config.") @staticmethod - def _get_job_name(job): + def _parse_job(job): if isinstance(job, dict): - return list(job)[0] - return job + job_name = list(job)[0] + job_cfg = job[job_name] + return job_name, job_cfg + return job, None - def _check_order_of_jobs(self, jobs, pipeline_name, allow_params=False): - if not allow_params: - for job in jobs: - if isinstance(job, dict): - self.fail("Setting parameters of jobs for '%s' pipeline " - "is permitted. Please fix '%s' job." % - (pipeline_name, self._get_job_name(job))) + def _check_order_of_jobs(self, pipeline): + jobs = self.project_cfg[pipeline]["jobs"] specific_jobs = ["rally-dsvm-tox-functional", "rally-docker-check", "rally-task-basic-with-existing-users", "rally-task-simple-job"] error_message = ( - "[%s pipeline] We are trying to display jobs in a specific order " - "to simplify search and reading. Tox jobs should go first in " - "alphabetic order. Next several specific jobs are expected (%s). " - "Next - all other jobs in alphabetic order." - % (pipeline_name, ", ".join(specific_jobs)) + f"[{pipeline} pipeline] We are trying to display jobs in a " + f"specific order to simplify search and reading. Tox jobs should " + f"go first in alphabetic order. Next several specific jobs are " + f"expected ({', '.join(specific_jobs)}). " + f"Next - all other jobs in alphabetic order." ) error_message += "\nPlease place '%s' at the position of '%s'." - jobs_names = [self._get_job_name(job) for job in jobs] + jobs_names = [self._parse_job(job)[0] for job in jobs] tox_jobs = sorted(job for job in jobs_names if job.startswith("rally-tox")) @@ -84,14 +84,67 @@ class RallyJobsTestCase(test.TestCase): self.fail(error_message % (job, jobs_names[i + j])) def test_order_of_displaying_jobs(self): - self._check_order_of_jobs( - self.project_cfg["check"]["jobs"], - pipeline_name="check", - allow_params=True - ) + for pipeline in ("check", "gate"): + self._check_order_of_jobs(pipeline=pipeline) - self._check_order_of_jobs( - self.project_cfg["gate"]["jobs"], - pipeline_name="gate", - allow_params=False - ) + JOB_FILES_PARAMS = {"files", "irrelevant-files"} + + def test_job_configs(self): + + file_matchers = {} + + for pipeline in ("check", "gate"): + for job in self.project_cfg[pipeline]["jobs"]: + job_name, job_cfg = self._parse_job(job) + if job_cfg is None: + continue + + if pipeline == "gate": + params = set(job_cfg) - self.JOB_FILES_PARAMS + if params: + self.fail( + f"Invalid parameter(s) for '{job_name}' job at " + f"gate pipeline: {', '.join(params)}.") + + for param in self.JOB_FILES_PARAMS: + if param in job_cfg: + for file_matcher in job_cfg[param]: + file_matchers.setdefault( + file_matcher, + { + "matcher": re.compile(file_matcher), + "used_by": [] + } + ) + file_matchers[file_matcher]["used_by"].append( + { + "pipeline": pipeline, + "job": job_name, + "param": param + } + ) + not_matched = set(file_matchers) + + for dir_name, _, files in os.walk(self.root_dir): + dir_name = os.path.relpath(dir_name, self.root_dir) + if dir_name in (".tox", ".git"): + continue + for f in files: + full_path = os.path.join(dir_name, f) + for key in list(not_matched): + if file_matchers[key]["matcher"].match(full_path): + not_matched.remove(key) + if not not_matched: + # stop iterating files if no more matchers to check + break + if not not_matched: + # stop iterating files if no more matchers to check + break + + for key in not_matched: + user = file_matchers[key]["used_by"][0] + self.fail( + f"'{user['job']}' job configuration for " + f"'{user['pipeline']}' pipeline includes wrong " + f"matcher '{key}' at '{user['param']}'." + )