diff --git a/doc/source/developer/testing.rst b/doc/source/developer/testing.rst index 4a813d059a..057ab7ef2b 100644 --- a/doc/source/developer/testing.rst +++ b/doc/source/developer/testing.rst @@ -9,6 +9,8 @@ Test classes that subclass :py:class:`~tests.base.ZuulTestCase` have access to a number of attributes useful for manipulating or inspecting the environment being simulated in the test: +.. autofunction:: tests.base.simple_layout + .. autoclass:: tests.base.ZuulTestCase :members: diff --git a/tests/base.py b/tests/base.py index 0c033b5e9f..120920bf82 100755 --- a/tests/base.py +++ b/tests/base.py @@ -97,6 +97,30 @@ def iterate_timeout(max_seconds, purpose): raise Exception("Timeout waiting for %s" % purpose) +def simple_layout(path): + """Specify a layout file for use by a test method. + + :arg str path: The path to the layout file. + + Some tests require only a very simple configuration. For those, + establishing a complete config directory hierachy is too much + work. In those cases, you can add a simple zuul.yaml file to the + test fixtures directory (in fixtures/layouts/foo.yaml) and use + this decorator to indicate the test method should use that rather + than the tenant config file specified by the test class. + + The decorator will cause that layout file to be added to a + config-project called "common-config" and each "project" instance + referenced in the layout file will have a git repo automatically + initialized. + """ + + def decorator(test): + test.__simple_layout__ = path + return test + return decorator + + class ChangeReference(git.Reference): _common_path_default = "refs/changes" _points_to_commits_only = True @@ -1231,7 +1255,8 @@ class ZuulTestCase(BaseTestCase): be loaded). It defaults to the value specified in `config_file` but can be overidden by subclasses to obtain a different tenant/project layout while using the standard main - configuration. + configuration. See also the :py:func:`simple_layout` + decorator. :cvar bool create_project_keys: Indicates whether Zuul should auto-generate keys for each project, or whether the test @@ -1324,7 +1349,6 @@ class ZuulTestCase(BaseTestCase): self.init_repo("org/conflict-project") self.init_repo("org/noop-project") self.init_repo("org/experimental-project") - self.init_repo("org/no-jobs-project") self.statsd = FakeStatsd() # note, use 127.0.0.1 rather than localhost to avoid getting ipv6 @@ -1452,19 +1476,70 @@ class ZuulTestCase(BaseTestCase): # obeys the config_file and tenant_config_file attributes. self.config = ConfigParser.ConfigParser() self.config.read(os.path.join(FIXTURE_DIR, self.config_file)) - if hasattr(self, 'tenant_config_file'): - self.config.set('zuul', 'tenant_config', self.tenant_config_file) - git_path = os.path.join( - os.path.dirname( - os.path.join(FIXTURE_DIR, self.tenant_config_file)), - 'git') - if os.path.exists(git_path): - for reponame in os.listdir(git_path): - project = reponame.replace('_', '/') - self.copyDirToRepo(project, - os.path.join(git_path, reponame)) + + if not self.setupSimpleLayout(): + if hasattr(self, 'tenant_config_file'): + self.config.set('zuul', 'tenant_config', + self.tenant_config_file) + git_path = os.path.join( + os.path.dirname( + os.path.join(FIXTURE_DIR, self.tenant_config_file)), + 'git') + if os.path.exists(git_path): + for reponame in os.listdir(git_path): + project = reponame.replace('_', '/') + self.copyDirToRepo(project, + os.path.join(git_path, reponame)) self.setupAllProjectKeys() + def setupSimpleLayout(self): + # If the test method has been decorated with a simple_layout, + # use that instead of the class tenant_config_file. Set up a + # single config-project with the specified layout, and + # initialize repos for all of the 'project' entries which + # appear in the layout. + test_name = self.id().split('.')[-1] + test = getattr(self, test_name) + if hasattr(test, '__simple_layout__'): + path = getattr(test, '__simple_layout__') + else: + return False + + path = os.path.join(FIXTURE_DIR, path) + with open(path) as f: + layout = yaml.safe_load(f.read()) + untrusted_projects = [] + for item in layout: + if 'project' in item: + name = item['project']['name'] + untrusted_projects.append(name) + self.init_repo(name) + self.addCommitToRepo(name, 'initial commit', + files={'README': ''}, + branch='master', tag='init') + + root = os.path.join(self.test_root, "config") + if not os.path.exists(root): + os.makedirs(root) + f = tempfile.NamedTemporaryFile(dir=root, delete=False) + config = [{'tenant': + {'name': 'tenant-one', + 'source': {'gerrit': + {'config-projects': ['common-config'], + 'untrusted-projects': untrusted_projects}}}}] + f.write(yaml.dump(config)) + f.close() + self.config.set('zuul', 'tenant_config', + os.path.join(FIXTURE_DIR, f.name)) + + self.init_repo('common-config') + with open(path) as f: + files = {'zuul.yaml': f.read()} + self.addCommitToRepo('common-config', 'add content from fixture', + files, branch='master', tag='init') + + return True + def setupAllProjectKeys(self): if self.create_project_keys: return @@ -1956,8 +2031,7 @@ class ZuulTestCase(BaseTestCase): - org/node-project - org/conflict-project - org/noop-project - - org/experimental-project - - org/no-jobs-project\n""" % path) + - org/experimental-project\n""" % path) for repo in untrusted_projects: f.write(" - %s\n" % repo) diff --git a/tests/fixtures/config/single-tenant/git/common-config/zuul.yaml b/tests/fixtures/config/single-tenant/git/common-config/zuul.yaml index b24f62eac4..141c78faab 100644 --- a/tests/fixtures/config/single-tenant/git/common-config/zuul.yaml +++ b/tests/fixtures/config/single-tenant/git/common-config/zuul.yaml @@ -225,9 +225,3 @@ dependencies: nonvoting-project-merge - nonvoting-project-test2: dependencies: nonvoting-project-merge - -- project: - name: org/no-jobs-project - check: - jobs: - - project-testfile diff --git a/tests/fixtures/config/single-tenant/git/org_no-jobs-project/README b/tests/fixtures/config/single-tenant/git/org_no-jobs-project/README deleted file mode 100644 index 44f3bacb96..0000000000 --- a/tests/fixtures/config/single-tenant/git/org_no-jobs-project/README +++ /dev/null @@ -1 +0,0 @@ -staypuft diff --git a/tests/fixtures/config/single-tenant/main.yaml b/tests/fixtures/config/single-tenant/main.yaml index e8a7fcba90..8c3e809c60 100644 --- a/tests/fixtures/config/single-tenant/main.yaml +++ b/tests/fixtures/config/single-tenant/main.yaml @@ -20,4 +20,3 @@ - org/conflict-project - org/noop-project - org/experimental-project - - org/no-jobs-project diff --git a/tests/fixtures/layouts/no-jobs-project.yaml b/tests/fixtures/layouts/no-jobs-project.yaml new file mode 100644 index 0000000000..803e5a025d --- /dev/null +++ b/tests/fixtures/layouts/no-jobs-project.yaml @@ -0,0 +1,23 @@ +- pipeline: + name: check + manager: independent + trigger: + gerrit: + - event: patchset-created + success: + gerrit: + verified: 1 + failure: + gerrit: + verified: -1 + +- job: + name: project-testfile + files: + - .*-requires + +- project: + name: org/no-jobs-project + check: + jobs: + - project-testfile diff --git a/tests/unit/test_scheduler.py b/tests/unit/test_scheduler.py index 22ae46dd7d..366354cf6c 100755 --- a/tests/unit/test_scheduler.py +++ b/tests/unit/test_scheduler.py @@ -36,6 +36,7 @@ import zuul.model from tests.base import ( ZuulTestCase, repack_repo, + simple_layout, ) @@ -1910,6 +1911,7 @@ class TestScheduler(ZuulTestCase): self.assertEqual(A.data['status'], 'MERGED') self.assertEqual(A.reported, 2) + @simple_layout('layouts/no-jobs-project.yaml') def test_no_job_project(self): "Test that reports with no jobs don't get sent" A = self.fake_gerrit.addFakeChange('org/no-jobs-project',