# Copyright 2012 Hewlett-Packard Development Company, L.P. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. import io import json import logging import os import textwrap import gc import time from unittest import skip import zuul.configloader from zuul.lib import encryption from tests.base import ( AnsibleZuulTestCase, ZuulTestCase, FIXTURE_DIR, simple_layout, ) class TestMultipleTenants(AnsibleZuulTestCase): # A temporary class to hold new tests while others are disabled tenant_config_file = 'config/multi-tenant/main.yaml' def test_multiple_tenants(self): A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A') A.addApproval('Code-Review', 2) self.fake_gerrit.addEvent(A.addApproval('Approved', 1)) self.waitUntilSettled() self.assertEqual(self.getJobFromHistory('project1-test1').result, 'SUCCESS') self.assertEqual(self.getJobFromHistory('python27').result, 'SUCCESS') self.assertEqual(A.data['status'], 'MERGED') self.assertEqual(A.reported, 2, "A should report start and success") self.assertIn('tenant-one-gate', A.messages[1], "A should transit tenant-one gate") self.assertNotIn('tenant-two-gate', A.messages[1], "A should *not* transit tenant-two gate") B = self.fake_gerrit.addFakeChange('org/project2', 'master', 'B') B.addApproval('Code-Review', 2) self.fake_gerrit.addEvent(B.addApproval('Approved', 1)) self.waitUntilSettled() self.assertEqual(self.getJobFromHistory('python27', 'org/project2').result, 'SUCCESS') self.assertEqual(self.getJobFromHistory('project2-test1').result, 'SUCCESS') self.assertEqual(B.data['status'], 'MERGED') self.assertEqual(B.reported, 2, "B should report start and success") self.assertIn('tenant-two-gate', B.messages[1], "B should transit tenant-two gate") self.assertNotIn('tenant-one-gate', B.messages[1], "B should *not* transit tenant-one gate") self.assertEqual(A.reported, 2, "Activity in tenant two should" "not affect tenant one") class TestProtected(ZuulTestCase): tenant_config_file = 'config/protected/main.yaml' def test_protected_ok(self): # test clean usage of final parent job in_repo_conf = textwrap.dedent( """ - job: name: job-protected protected: true run: playbooks/job-protected.yaml - project: name: org/project check: jobs: - job-child-ok - job: name: job-child-ok parent: job-protected - project: name: org/project check: jobs: - job-child-ok """) file_dict = {'zuul.yaml': in_repo_conf} A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A', files=file_dict) self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1)) self.waitUntilSettled() self.assertEqual(A.reported, 1) self.assertEqual(A.patchsets[-1]['approvals'][0]['value'], '1') def test_protected_reset(self): # try to reset protected flag in_repo_conf = textwrap.dedent( """ - job: name: job-protected protected: true run: playbooks/job-protected.yaml - job: name: job-child-reset-protected parent: job-protected protected: false - project: name: org/project check: jobs: - job-child-reset-protected """) file_dict = {'zuul.yaml': in_repo_conf} A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A', files=file_dict) self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1)) self.waitUntilSettled() # The second patch tried to override some variables. # Thus it should fail. self.assertEqual(A.reported, 1) self.assertEqual(A.patchsets[-1]['approvals'][0]['value'], '-1') self.assertIn('Unable to reset protected attribute', A.messages[0]) def test_protected_inherit_not_ok(self): # try to inherit from a protected job in different project in_repo_conf = textwrap.dedent( """ - job: name: job-child-notok run: playbooks/job-child-notok.yaml parent: job-protected - project: name: org/project1 check: jobs: - job-child-notok """) file_dict = {'zuul.yaml': in_repo_conf} A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A', files=file_dict) self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1)) self.waitUntilSettled() self.assertEqual(A.reported, 1) self.assertEqual(A.patchsets[-1]['approvals'][0]['value'], '-1') self.assertIn( "which is defined in review.example.com/org/project is protected " "and cannot be inherited from other projects.", A.messages[0]) class TestAbstract(ZuulTestCase): tenant_config_file = 'config/abstract/main.yaml' def test_abstract_fail(self): in_repo_conf = textwrap.dedent( """ - project: check: jobs: - job-abstract """) file_dict = {'zuul.yaml': in_repo_conf} A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A', files=file_dict) self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1)) self.waitUntilSettled() self.assertEqual(A.reported, 1) self.assertEqual(A.patchsets[-1]['approvals'][0]['value'], '-1') self.assertIn('may not be directly run', A.messages[0]) def test_child_of_abstract(self): in_repo_conf = textwrap.dedent( """ - project: check: jobs: - job-child """) file_dict = {'zuul.yaml': in_repo_conf} A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A', files=file_dict) self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1)) self.waitUntilSettled() self.assertEqual(A.reported, 1) self.assertEqual(A.patchsets[-1]['approvals'][0]['value'], '1') class TestFinal(ZuulTestCase): tenant_config_file = 'config/final/main.yaml' def test_final_variant_ok(self): # test clean usage of final parent job in_repo_conf = textwrap.dedent( """ - project: name: org/project check: jobs: - job-final """) file_dict = {'.zuul.yaml': in_repo_conf} A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A', files=file_dict) self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1)) self.waitUntilSettled() self.assertEqual(A.reported, 1) self.assertEqual(A.patchsets[-1]['approvals'][0]['value'], '1') def test_final_variant_error(self): # test misuse of final parent job in_repo_conf = textwrap.dedent( """ - project: name: org/project check: jobs: - job-final: vars: dont_override_this: bar """) file_dict = {'.zuul.yaml': in_repo_conf} A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A', files=file_dict) self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1)) self.waitUntilSettled() # The second patch tried to override some variables. # Thus it should fail. self.assertEqual(A.reported, 1) self.assertEqual(A.patchsets[-1]['approvals'][0]['value'], '-1') self.assertIn('Unable to modify final job', A.messages[0]) def test_final_inheritance(self): # test misuse of final parent job in_repo_conf = textwrap.dedent( """ - job: name: project-test parent: job-final run: playbooks/project-test.yaml - project: name: org/project check: jobs: - project-test """) in_repo_playbook = textwrap.dedent( """ - hosts: all tasks: [] """) file_dict = {'.zuul.yaml': in_repo_conf, 'playbooks/project-test.yaml': in_repo_playbook} A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A', files=file_dict) self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1)) self.waitUntilSettled() # The second patch tried to override some variables. # Thus it should fail. self.assertEqual(A.reported, 1) self.assertEqual(A.patchsets[-1]['approvals'][0]['value'], '-1') self.assertIn('Unable to modify final job', A.messages[0]) class TestBranchDeletion(ZuulTestCase): tenant_config_file = 'config/branch-deletion/main.yaml' def test_branch_delete(self): # This tests a tenant reconfiguration on deleting a branch # *after* an earlier failed tenant reconfiguration. This # ensures that cached data are appropriately removed, even if # we are recovering from an invalid config. self.create_branch('org/project', 'stable/queens') self.fake_gerrit.addEvent( self.fake_gerrit.getFakeBranchCreatedEvent( 'org/project', 'stable/queens')) self.waitUntilSettled() in_repo_conf = textwrap.dedent( """ - project: check: jobs: - nonexistent-job """) file_dict = {'zuul.yaml': in_repo_conf} A = self.fake_gerrit.addFakeChange('org/project', 'stable/queens', 'A', files=file_dict) A.setMerged() self.fake_gerrit.addEvent(A.getChangeMergedEvent()) self.waitUntilSettled() self.delete_branch('org/project', 'stable/queens') self.fake_gerrit.addEvent( self.fake_gerrit.getFakeBranchDeletedEvent( 'org/project', 'stable/queens')) self.waitUntilSettled() in_repo_conf = textwrap.dedent( """ - project: check: jobs: - base """) file_dict = {'zuul.yaml': in_repo_conf} B = self.fake_gerrit.addFakeChange('org/project1', 'master', 'B', files=file_dict) self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1)) self.waitUntilSettled() self.assertEqual(B.reported, 1) self.assertHistory([ dict(name='base', result='SUCCESS', changes='2,1')]) def test_branch_delete_full_reconfiguration(self): # This tests a full configuration after deleting a branch # *after* an earlier failed tenant reconfiguration. This # ensures that cached data are appropriately removed, even if # we are recovering from an invalid config. self.create_branch('org/project', 'stable/queens') self.fake_gerrit.addEvent( self.fake_gerrit.getFakeBranchCreatedEvent( 'org/project', 'stable/queens')) self.waitUntilSettled() in_repo_conf = textwrap.dedent( """ - project: check: jobs: - nonexistent-job """) file_dict = {'zuul.yaml': in_repo_conf} A = self.fake_gerrit.addFakeChange('org/project', 'stable/queens', 'A', files=file_dict) A.setMerged() self.fake_gerrit.addEvent(A.getChangeMergedEvent()) self.waitUntilSettled() self.delete_branch('org/project', 'stable/queens') self.sched.reconfigure(self.config) self.waitUntilSettled() in_repo_conf = textwrap.dedent( """ - project: check: jobs: - base """) file_dict = {'zuul.yaml': in_repo_conf} B = self.fake_gerrit.addFakeChange('org/project1', 'master', 'B', files=file_dict) self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1)) self.waitUntilSettled() self.assertEqual(B.reported, 1) self.assertHistory([ dict(name='base', result='SUCCESS', changes='2,1')]) class TestBranchTag(ZuulTestCase): tenant_config_file = 'config/branch-tag/main.yaml' def test_no_branch_match(self): # Test that tag jobs run with no explicit branch matchers event = self.fake_gerrit.addFakeTag('org/project', 'master', 'foo') self.fake_gerrit.addEvent(event) self.waitUntilSettled() self.assertHistory([ dict(name='central-job', result='SUCCESS', ref='refs/tags/foo'), dict(name='test-job', result='SUCCESS', ref='refs/tags/foo')], ordered=False) def test_no_branch_match_multi_branch(self): # Test that tag jobs run with no explicit branch matchers in a # multi-branch project (where jobs generally get implied # branch matchers) self.create_branch('org/project', 'stable/pike') self.fake_gerrit.addEvent( self.fake_gerrit.getFakeBranchCreatedEvent( 'org/project', 'stable/pike')) self.waitUntilSettled() event = self.fake_gerrit.addFakeTag('org/project', 'master', 'foo') self.fake_gerrit.addEvent(event) self.waitUntilSettled() # test-job does not run in this case because it is defined in # a branched repo with implied branch matchers. A release job # defined in a multi-branch repo would need at least one # top-level variant with no branch matcher in order to match a # tag. self.assertHistory([ dict(name='central-job', result='SUCCESS', ref='refs/tags/foo')]) class TestBranchNegative(ZuulTestCase): tenant_config_file = 'config/branch-negative/main.yaml' def test_negative_branch_match(self): # Test that a negative branch matcher works with implied branches. self.create_branch('org/project', 'stable/pike') self.fake_gerrit.addEvent( self.fake_gerrit.getFakeBranchCreatedEvent( 'org/project', 'stable/pike')) self.waitUntilSettled() A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A') self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1)) self.waitUntilSettled() B = self.fake_gerrit.addFakeChange('org/project', 'stable/pike', 'A') self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1)) self.waitUntilSettled() self.assertHistory([ dict(name='test-job', result='SUCCESS', changes='1,1')]) class TestBranchTemplates(ZuulTestCase): tenant_config_file = 'config/branch-templates/main.yaml' def test_template_removal_from_branch(self): # Test that a template can be removed from one branch but not # another. # This creates a new branch with a copy of the config in master self.create_branch('puppet-integration', 'stable/newton') self.create_branch('puppet-integration', 'stable/ocata') self.create_branch('puppet-tripleo', 'stable/newton') self.create_branch('puppet-tripleo', 'stable/ocata') self.fake_gerrit.addEvent( self.fake_gerrit.getFakeBranchCreatedEvent( 'puppet-integration', 'stable/newton')) self.fake_gerrit.addEvent( self.fake_gerrit.getFakeBranchCreatedEvent( 'puppet-integration', 'stable/ocata')) self.fake_gerrit.addEvent( self.fake_gerrit.getFakeBranchCreatedEvent( 'puppet-tripleo', 'stable/newton')) self.fake_gerrit.addEvent( self.fake_gerrit.getFakeBranchCreatedEvent( 'puppet-tripleo', 'stable/ocata')) self.waitUntilSettled() in_repo_conf = textwrap.dedent( """ - project: name: puppet-tripleo check: jobs: - puppet-something """) file_dict = {'.zuul.yaml': in_repo_conf} A = self.fake_gerrit.addFakeChange('puppet-tripleo', 'stable/newton', 'A', files=file_dict) self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1)) self.waitUntilSettled() self.assertHistory([ dict(name='puppet-something', result='SUCCESS', changes='1,1')]) def test_template_change_on_branch(self): # Test that the contents of a template can be changed on one # branch without affecting another. # This creates a new branch with a copy of the config in master self.create_branch('puppet-integration', 'stable/newton') self.create_branch('puppet-integration', 'stable/ocata') self.create_branch('puppet-tripleo', 'stable/newton') self.create_branch('puppet-tripleo', 'stable/ocata') self.fake_gerrit.addEvent( self.fake_gerrit.getFakeBranchCreatedEvent( 'puppet-integration', 'stable/newton')) self.fake_gerrit.addEvent( self.fake_gerrit.getFakeBranchCreatedEvent( 'puppet-integration', 'stable/ocata')) self.fake_gerrit.addEvent( self.fake_gerrit.getFakeBranchCreatedEvent( 'puppet-tripleo', 'stable/newton')) self.fake_gerrit.addEvent( self.fake_gerrit.getFakeBranchCreatedEvent( 'puppet-tripleo', 'stable/ocata')) self.waitUntilSettled() in_repo_conf = textwrap.dedent(""" - job: name: puppet-unit-base run: playbooks/run-unit-tests.yaml - job: name: puppet-unit-3.8 parent: puppet-unit-base branches: ^(stable/(newton|ocata)).*$ vars: puppet_gem_version: 3.8 - job: name: puppet-something run: playbooks/run-unit-tests.yaml - project-template: name: puppet-unit check: jobs: - puppet-something - project: name: puppet-integration templates: - puppet-unit """) file_dict = {'.zuul.yaml': in_repo_conf} A = self.fake_gerrit.addFakeChange('puppet-integration', 'stable/newton', 'A', files=file_dict) B = self.fake_gerrit.addFakeChange('puppet-tripleo', 'stable/newton', 'B') B.data['commitMessage'] = '%s\n\nDepends-On: %s\n' % ( B.subject, A.data['id']) self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1)) self.waitUntilSettled() self.assertHistory([ dict(name='puppet-something', result='SUCCESS', changes='1,1 2,1')]) class TestBranchVariants(ZuulTestCase): tenant_config_file = 'config/branch-variants/main.yaml' def test_branch_variants(self): # Test branch variants of jobs with inheritance self.executor_server.hold_jobs_in_build = True # This creates a new branch with a copy of the config in master self.create_branch('puppet-integration', 'stable') self.fake_gerrit.addEvent( self.fake_gerrit.getFakeBranchCreatedEvent( 'puppet-integration', 'stable')) self.waitUntilSettled() A = self.fake_gerrit.addFakeChange('puppet-integration', 'stable', 'A') self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1)) self.waitUntilSettled() self.assertEqual(len(self.builds[0].parameters['pre_playbooks']), 3) self.executor_server.hold_jobs_in_build = False self.executor_server.release() self.waitUntilSettled() def test_branch_variants_reconfigure(self): # Test branch variants of jobs with inheritance self.executor_server.hold_jobs_in_build = True # This creates a new branch with a copy of the config in master self.create_branch('puppet-integration', 'stable') self.fake_gerrit.addEvent( self.fake_gerrit.getFakeBranchCreatedEvent( 'puppet-integration', 'stable')) self.waitUntilSettled() with open(os.path.join(FIXTURE_DIR, 'config/branch-variants/git/', 'puppet-integration/.zuul.yaml')) as f: config = f.read() # Push a change that triggers a dynamic reconfiguration file_dict = {'.zuul.yaml': config} A = self.fake_gerrit.addFakeChange('puppet-integration', 'master', 'A', files=file_dict) self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1)) self.waitUntilSettled() ipath = self.builds[0].parameters['zuul']['_inheritance_path'] for i in ipath: self.log.debug("inheritance path %s", i) self.assertEqual(len(ipath), 5) self.executor_server.hold_jobs_in_build = False self.executor_server.release() self.waitUntilSettled() def test_branch_variants_divergent(self): # Test branches can diverge and become independent self.executor_server.hold_jobs_in_build = True # This creates a new branch with a copy of the config in master self.create_branch('puppet-integration', 'stable') self.fake_gerrit.addEvent( self.fake_gerrit.getFakeBranchCreatedEvent( 'puppet-integration', 'stable')) self.waitUntilSettled() with open(os.path.join(FIXTURE_DIR, 'config/branch-variants/git/', 'puppet-integration/stable.zuul.yaml')) as f: config = f.read() file_dict = {'.zuul.yaml': config} C = self.fake_gerrit.addFakeChange('puppet-integration', 'stable', 'C', files=file_dict) C.addApproval('Code-Review', 2) self.fake_gerrit.addEvent(C.addApproval('Approved', 1)) self.waitUntilSettled() self.fake_gerrit.addEvent(C.getChangeMergedEvent()) self.waitUntilSettled() A = self.fake_gerrit.addFakeChange('puppet-integration', 'master', 'A') self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1)) self.waitUntilSettled() B = self.fake_gerrit.addFakeChange('puppet-integration', 'stable', 'B') self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1)) self.waitUntilSettled() self.assertEqual(self.builds[0].parameters['zuul']['jobtags'], ['master']) self.assertEqual(self.builds[1].parameters['zuul']['jobtags'], ['stable']) self.executor_server.hold_jobs_in_build = False self.executor_server.release() self.waitUntilSettled() class TestBranchMismatch(ZuulTestCase): tenant_config_file = 'config/branch-mismatch/main.yaml' def test_job_override_branch(self): "Test that override-checkout overrides branch matchers as well" # Make sure the parent job repo is branched, so it gets # implied branch matchers. self.create_branch('org/project1', 'stable') self.fake_gerrit.addEvent( self.fake_gerrit.getFakeBranchCreatedEvent( 'org/project1', 'stable')) # The child job repo should have a branch which does not exist # in the parent job repo. self.create_branch('org/project2', 'devel') self.fake_gerrit.addEvent( self.fake_gerrit.getFakeBranchCreatedEvent( 'org/project2', 'devel')) # A job in a repo with a weird branch name should use the # parent job from the parent job's master (default) branch. A = self.fake_gerrit.addFakeChange('org/project2', 'devel', 'A') self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1)) self.waitUntilSettled() # project-test2 should run because it inherits from # project-test1 and we will use the fallback branch to find # project-test1 variants, but project-test1 itself, even # though it is in the project-pipeline config, should not run # because it doesn't directly match. self.assertHistory([ dict(name='project-test1', result='SUCCESS', changes='1,1'), dict(name='project-test2', result='SUCCESS', changes='1,1'), ], ordered=False) class TestAllowedProjects(ZuulTestCase): tenant_config_file = 'config/allowed-projects/main.yaml' def test_allowed_projects(self): A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A') self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1)) self.waitUntilSettled() self.assertEqual(A.reported, 1) self.assertIn('Build succeeded', A.messages[0]) B = self.fake_gerrit.addFakeChange('org/project2', 'master', 'B') self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1)) self.waitUntilSettled() self.assertEqual(B.reported, 1) self.assertIn('Project org/project2 is not allowed ' 'to run job test-project2', B.messages[0]) C = self.fake_gerrit.addFakeChange('org/project3', 'master', 'C') self.fake_gerrit.addEvent(C.getPatchsetCreatedEvent(1)) self.waitUntilSettled() self.assertEqual(C.reported, 1) self.assertIn('Project org/project3 is not allowed ' 'to run job restricted-job', C.messages[0]) self.assertHistory([ dict(name='test-project1', result='SUCCESS', changes='1,1'), dict(name='restricted-job', result='SUCCESS', changes='1,1'), ], ordered=False) class TestCentralJobs(ZuulTestCase): tenant_config_file = 'config/central-jobs/main.yaml' def setUp(self): super(TestCentralJobs, self).setUp() self.create_branch('org/project', 'stable') self.fake_gerrit.addEvent( self.fake_gerrit.getFakeBranchCreatedEvent( 'org/project', 'stable')) self.waitUntilSettled() def _updateConfig(self, config, branch): file_dict = {'.zuul.yaml': config} C = self.fake_gerrit.addFakeChange('org/project', branch, 'C', files=file_dict) C.addApproval('Code-Review', 2) self.fake_gerrit.addEvent(C.addApproval('Approved', 1)) self.waitUntilSettled() self.fake_gerrit.addEvent(C.getChangeMergedEvent()) self.waitUntilSettled() def _test_central_job_on_branch(self, branch, other_branch): # Test that a job defined on a branchless repo only runs on # the branch applied config = textwrap.dedent( """ - project: name: org/project check: jobs: - central-job """) self._updateConfig(config, branch) A = self.fake_gerrit.addFakeChange('org/project', branch, 'A') self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1)) self.waitUntilSettled() self.assertHistory([ dict(name='central-job', result='SUCCESS', changes='2,1')]) # No jobs should run for this change. B = self.fake_gerrit.addFakeChange('org/project', other_branch, 'B') self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1)) self.waitUntilSettled() self.assertHistory([ dict(name='central-job', result='SUCCESS', changes='2,1')]) def test_central_job_on_stable(self): self._test_central_job_on_branch('master', 'stable') def test_central_job_on_master(self): self._test_central_job_on_branch('stable', 'master') def _test_central_template_on_branch(self, branch, other_branch): # Test that a project-template defined on a branchless repo # only runs on the branch applied config = textwrap.dedent( """ - project: name: org/project templates: ['central-jobs'] """) self._updateConfig(config, branch) A = self.fake_gerrit.addFakeChange('org/project', branch, 'A') self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1)) self.waitUntilSettled() self.assertHistory([ dict(name='central-job', result='SUCCESS', changes='2,1')]) # No jobs should run for this change. B = self.fake_gerrit.addFakeChange('org/project', other_branch, 'B') self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1)) self.waitUntilSettled() self.assertHistory([ dict(name='central-job', result='SUCCESS', changes='2,1')]) def test_central_template_on_stable(self): self._test_central_template_on_branch('master', 'stable') def test_central_template_on_master(self): self._test_central_template_on_branch('stable', 'master') class TestInRepoConfig(ZuulTestCase): # A temporary class to hold new tests while others are disabled config_file = 'zuul-connections-gerrit-and-github.conf' tenant_config_file = 'config/in-repo/main.yaml' def test_in_repo_config(self): A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A') A.addApproval('Code-Review', 2) self.fake_gerrit.addEvent(A.addApproval('Approved', 1)) self.waitUntilSettled() self.assertEqual(self.getJobFromHistory('project-test1').result, 'SUCCESS') self.assertEqual(A.data['status'], 'MERGED') self.assertEqual(A.reported, 2, "A should report start and success") self.assertIn('tenant-one-gate', A.messages[1], "A should transit tenant-one gate") @skip("This test is useful, but not reliable") def test_full_and_dynamic_reconfig(self): self.executor_server.hold_jobs_in_build = True in_repo_conf = textwrap.dedent( """ - job: name: project-test1 - project: name: org/project tenant-one-gate: jobs: - project-test1 """) file_dict = {'.zuul.yaml': in_repo_conf} A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A', files=file_dict) A.addApproval('Code-Review', 2) self.fake_gerrit.addEvent(A.addApproval('Approved', 1)) self.waitUntilSettled() self.sched.reconfigure(self.config) self.waitUntilSettled() gc.collect() pipelines = [obj for obj in gc.get_objects() if isinstance(obj, zuul.model.Pipeline)] self.assertEqual(len(pipelines), 4) self.executor_server.hold_jobs_in_build = False self.executor_server.release() self.waitUntilSettled() def test_dynamic_config(self): in_repo_conf = textwrap.dedent( """ - job: name: project-test1 - job: name: project-test2 run: playbooks/project-test2.yaml - job: name: project-test3 run: playbooks/project-test2.yaml # add a job by the short project name - project: name: org/project tenant-one-gate: jobs: - project-test2 # add a job by the canonical project name - project: name: review.example.com/org/project tenant-one-gate: jobs: - project-test3 """) in_repo_playbook = textwrap.dedent( """ - hosts: all tasks: [] """) file_dict = {'.zuul.yaml': in_repo_conf, 'playbooks/project-test2.yaml': in_repo_playbook} A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A', files=file_dict) A.addApproval('Code-Review', 2) self.fake_gerrit.addEvent(A.addApproval('Approved', 1)) self.waitUntilSettled() self.assertEqual(A.data['status'], 'MERGED') self.assertEqual(A.reported, 2, "A should report start and success") self.assertIn('tenant-one-gate', A.messages[1], "A should transit tenant-one gate") self.assertHistory([ dict(name='project-test2', result='SUCCESS', changes='1,1'), dict(name='project-test3', result='SUCCESS', changes='1,1'), ], ordered=False) self.fake_gerrit.addEvent(A.getChangeMergedEvent()) self.waitUntilSettled() # Now that the config change is landed, it should be live for # subsequent changes. B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B') B.addApproval('Code-Review', 2) self.fake_gerrit.addEvent(B.addApproval('Approved', 1)) self.waitUntilSettled() self.assertEqual(self.getJobFromHistory('project-test2').result, 'SUCCESS') self.assertHistory([ dict(name='project-test2', result='SUCCESS', changes='1,1'), dict(name='project-test3', result='SUCCESS', changes='1,1'), dict(name='project-test2', result='SUCCESS', changes='2,1'), dict(name='project-test3', result='SUCCESS', changes='2,1'), ], ordered=False) def test_dynamic_template(self): # Tests that a project can't update a template in another # project. in_repo_conf = textwrap.dedent( """ - job: name: project-test1 - project-template: name: common-config-template check: jobs: - project-test1 - project: name: org/project templates: [common-config-template] """) file_dict = {'.zuul.yaml': in_repo_conf} A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A', files=file_dict) self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1)) self.waitUntilSettled() self.assertEqual(A.patchsets[0]['approvals'][0]['value'], "-1") self.assertIn('Project template common-config-template ' 'is already defined', A.messages[0], "A should have failed the check pipeline") def test_dynamic_config_errors_not_accumulated(self): """Test that requesting broken dynamic configs does not appear in tenant layout error accumulator""" in_repo_conf = textwrap.dedent( """ - job: name: project-test1 - project: name: org/project check: jobs: - non-existent-job """) in_repo_playbook = textwrap.dedent( """ - hosts: all tasks: [] """) file_dict = {'.zuul.yaml': in_repo_conf, 'playbooks/project-test2.yaml': in_repo_playbook} A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A', files=file_dict) self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1)) self.waitUntilSettled() tenant = self.sched.abide.tenants.get('tenant-one') self.assertEquals( len(tenant.layout.loading_errors), 0, "No error should have been accumulated") self.assertHistory([]) def test_dynamic_config_non_existing_job(self): """Test that requesting a non existent job fails""" in_repo_conf = textwrap.dedent( """ - job: name: project-test1 - project: name: org/project check: jobs: - non-existent-job """) in_repo_playbook = textwrap.dedent( """ - hosts: all tasks: [] """) file_dict = {'.zuul.yaml': in_repo_conf, 'playbooks/project-test2.yaml': in_repo_playbook} A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A', files=file_dict) self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1)) self.waitUntilSettled() self.assertEqual(A.reported, 1, "A should report failure") self.assertEqual(A.patchsets[0]['approvals'][0]['value'], "-1") self.assertIn('Job non-existent-job not defined', A.messages[0], "A should have failed the check pipeline") self.assertHistory([]) def test_dynamic_config_non_existing_job_in_template(self): """Test that requesting a non existent job fails""" in_repo_conf = textwrap.dedent( """ - job: name: project-test1 - project-template: name: test-template check: jobs: - non-existent-job - project: name: org/project templates: - test-template """) in_repo_playbook = textwrap.dedent( """ - hosts: all tasks: [] """) file_dict = {'.zuul.yaml': in_repo_conf, 'playbooks/project-test2.yaml': in_repo_playbook} A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A', files=file_dict) self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1)) self.waitUntilSettled() self.assertEqual(A.reported, 1, "A should report failure") self.assertEqual(A.patchsets[0]['approvals'][0]['value'], "-1") self.assertIn('Job non-existent-job not defined', A.messages[0], "A should have failed the check pipeline") self.assertHistory([]) def test_dynamic_config_new_patchset(self): self.executor_server.hold_jobs_in_build = True tenant = self.sched.abide.tenants.get('tenant-one') check_pipeline = tenant.layout.pipelines['check'] in_repo_conf = textwrap.dedent( """ - job: name: project-test1 run: playbooks/project-test1.yaml - job: name: project-test2 run: playbooks/project-test2.yaml - project: name: org/project check: jobs: - project-test2 """) in_repo_playbook = textwrap.dedent( """ - hosts: all tasks: [] """) file_dict = {'.zuul.yaml': in_repo_conf, 'playbooks/project-test2.yaml': in_repo_playbook} A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A', files=file_dict) self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1)) self.waitUntilSettled() items = check_pipeline.getAllItems() self.assertEqual(items[0].change.number, '1') self.assertEqual(items[0].change.patchset, '1') self.assertTrue(items[0].live) in_repo_conf = textwrap.dedent( """ - job: name: project-test1 run: playbooks/project-test1.yaml - job: name: project-test2 run: playbooks/project-test2.yaml - project: name: org/project check: jobs: - project-test1 - project-test2 """) file_dict = {'.zuul.yaml': in_repo_conf, 'playbooks/project-test2.yaml': in_repo_playbook} A.addPatchset(files=file_dict) self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(2)) self.waitUntilSettled() items = check_pipeline.getAllItems() self.assertEqual(items[0].change.number, '1') self.assertEqual(items[0].change.patchset, '2') self.assertTrue(items[0].live) self.executor_server.hold_jobs_in_build = False self.executor_server.release('project-test1') self.waitUntilSettled() self.executor_server.release() self.waitUntilSettled() self.assertHistory([ dict(name='project-test2', result='ABORTED', changes='1,1'), dict(name='project-test1', result='SUCCESS', changes='1,2'), dict(name='project-test2', result='SUCCESS', changes='1,2')]) def test_in_repo_branch(self): in_repo_conf = textwrap.dedent( """ - job: name: project-test1 - job: name: project-test2 run: playbooks/project-test2.yaml - project: name: org/project tenant-one-gate: jobs: - project-test2 """) in_repo_playbook = textwrap.dedent( """ - hosts: all tasks: [] """) file_dict = {'.zuul.yaml': in_repo_conf, 'playbooks/project-test2.yaml': in_repo_playbook} self.create_branch('org/project', 'stable') self.fake_gerrit.addEvent( self.fake_gerrit.getFakeBranchCreatedEvent( 'org/project', 'stable')) self.waitUntilSettled() A = self.fake_gerrit.addFakeChange('org/project', 'stable', 'A', files=file_dict) A.addApproval('Code-Review', 2) self.fake_gerrit.addEvent(A.addApproval('Approved', 1)) self.waitUntilSettled() self.assertEqual(A.data['status'], 'MERGED') self.assertEqual(A.reported, 2, "A should report start and success") self.assertIn('tenant-one-gate', A.messages[1], "A should transit tenant-one gate") self.assertHistory([ dict(name='project-test2', result='SUCCESS', changes='1,1')]) self.fake_gerrit.addEvent(A.getChangeMergedEvent()) self.waitUntilSettled() # The config change should not affect master. B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B') B.addApproval('Code-Review', 2) self.fake_gerrit.addEvent(B.addApproval('Approved', 1)) self.waitUntilSettled() self.assertHistory([ dict(name='project-test2', result='SUCCESS', changes='1,1'), dict(name='project-test1', result='SUCCESS', changes='2,1')]) # The config change should be live for further changes on # stable. C = self.fake_gerrit.addFakeChange('org/project', 'stable', 'C') C.addApproval('Code-Review', 2) self.fake_gerrit.addEvent(C.addApproval('Approved', 1)) self.waitUntilSettled() self.assertHistory([ dict(name='project-test2', result='SUCCESS', changes='1,1'), dict(name='project-test1', result='SUCCESS', changes='2,1'), dict(name='project-test2', result='SUCCESS', changes='3,1')]) def test_crd_dynamic_config_branch(self): # Test that we can create a job in one repo and be able to use # it from a different branch on a different repo. self.create_branch('org/project1', 'stable') self.fake_gerrit.addEvent( self.fake_gerrit.getFakeBranchCreatedEvent( 'org/project1', 'stable')) in_repo_conf = textwrap.dedent( """ - job: name: project-test1 - job: name: project-test2 run: playbooks/project-test2.yaml - project: name: org/project check: jobs: - project-test2 """) in_repo_playbook = textwrap.dedent( """ - hosts: all tasks: [] """) file_dict = {'.zuul.yaml': in_repo_conf, 'playbooks/project-test2.yaml': in_repo_playbook} A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A', files=file_dict) second_repo_conf = textwrap.dedent( """ - project: name: org/project1 check: jobs: - project-test2 """) second_file_dict = {'.zuul.yaml': second_repo_conf} B = self.fake_gerrit.addFakeChange('org/project1', 'stable', 'B', files=second_file_dict) B.data['commitMessage'] = '%s\n\nDepends-On: %s\n' % ( B.subject, A.data['id']) self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1)) self.waitUntilSettled() self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1)) self.waitUntilSettled() self.assertEqual(A.reported, 1, "A should report") self.assertHistory([ dict(name='project-test2', result='SUCCESS', changes='1,1'), dict(name='project-test2', result='SUCCESS', changes='1,1 2,1'), ]) def test_yaml_list_error(self): in_repo_conf = textwrap.dedent( """ job: foo """) file_dict = {'.zuul.yaml': in_repo_conf} A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A', files=file_dict) A.addApproval('Code-Review', 2) self.fake_gerrit.addEvent(A.addApproval('Approved', 1)) self.waitUntilSettled() self.assertEqual(A.data['status'], 'NEW') self.assertEqual(A.reported, 1, "A should report failure") self.assertIn('not a list', A.messages[0], "A should have a syntax error reported") def test_yaml_dict_error(self): in_repo_conf = textwrap.dedent( """ - job """) file_dict = {'.zuul.yaml': in_repo_conf} A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A', files=file_dict) A.addApproval('Code-Review', 2) self.fake_gerrit.addEvent(A.addApproval('Approved', 1)) self.waitUntilSettled() self.assertEqual(A.data['status'], 'NEW') self.assertEqual(A.reported, 1, "A should report failure") self.assertIn('not a dictionary', A.messages[0], "A should have a syntax error reported") def test_yaml_duplicate_key_error(self): in_repo_conf = textwrap.dedent( """ - job: name: foo name: bar """) file_dict = {'.zuul.yaml': in_repo_conf} A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A', files=file_dict) A.addApproval('Code-Review', 2) self.fake_gerrit.addEvent(A.addApproval('Approved', 1)) self.waitUntilSettled() self.assertEqual(A.data['status'], 'NEW') self.assertEqual(A.reported, 1, "A should report failure") self.assertIn('appears more than once', A.messages[0], "A should have a syntax error reported") def test_yaml_key_error(self): in_repo_conf = textwrap.dedent( """ - job: name: project-test2 """) file_dict = {'.zuul.yaml': in_repo_conf} A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A', files=file_dict) A.addApproval('Code-Review', 2) self.fake_gerrit.addEvent(A.addApproval('Approved', 1)) self.waitUntilSettled() self.assertEqual(A.data['status'], 'NEW') self.assertEqual(A.reported, 1, "A should report failure") self.assertIn('has more than one key', A.messages[0], "A should have a syntax error reported") def test_yaml_unknown_error(self): in_repo_conf = textwrap.dedent( """ - foobar: foo: bar """) file_dict = {'.zuul.yaml': in_repo_conf} A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A', files=file_dict) A.addApproval('Code-Review', 2) self.fake_gerrit.addEvent(A.addApproval('Approved', 1)) self.waitUntilSettled() self.assertEqual(A.data['status'], 'NEW') self.assertEqual(A.reported, 1, "A should report failure") self.assertIn('not recognized', A.messages[0], "A should have a syntax error reported") def test_untrusted_syntax_error(self): in_repo_conf = textwrap.dedent( """ - job: name: project-test2 foo: error """) file_dict = {'.zuul.yaml': in_repo_conf} A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A', files=file_dict) A.addApproval('Code-Review', 2) self.fake_gerrit.addEvent(A.addApproval('Approved', 1)) self.waitUntilSettled() self.assertEqual(A.data['status'], 'NEW') self.assertEqual(A.reported, 1, "A should report failure") self.assertIn('syntax error', A.messages[0], "A should have a syntax error reported") def test_trusted_syntax_error(self): in_repo_conf = textwrap.dedent( """ - job: name: project-test2 foo: error """) file_dict = {'zuul.yaml': in_repo_conf} A = self.fake_gerrit.addFakeChange('common-config', 'master', 'A', files=file_dict) A.addApproval('Code-Review', 2) self.fake_gerrit.addEvent(A.addApproval('Approved', 1)) self.waitUntilSettled() self.assertEqual(A.data['status'], 'NEW') self.assertEqual(A.reported, 1, "A should report failure") self.assertIn('syntax error', A.messages[0], "A should have a syntax error reported") def test_untrusted_yaml_error(self): in_repo_conf = textwrap.dedent( """ - job: foo: error """) file_dict = {'.zuul.yaml': in_repo_conf} A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A', files=file_dict) A.addApproval('Code-Review', 2) self.fake_gerrit.addEvent(A.addApproval('Approved', 1)) self.waitUntilSettled() self.assertEqual(A.data['status'], 'NEW') self.assertEqual(A.reported, 1, "A should report failure") self.assertIn('syntax error', A.messages[0], "A should have a syntax error reported") def test_untrusted_shadow_error(self): in_repo_conf = textwrap.dedent( """ - job: name: common-config-test """) file_dict = {'.zuul.yaml': in_repo_conf} A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A', files=file_dict) A.addApproval('Code-Review', 2) self.fake_gerrit.addEvent(A.addApproval('Approved', 1)) self.waitUntilSettled() self.assertEqual(A.data['status'], 'NEW') self.assertEqual(A.reported, 1, "A should report failure") self.assertIn('not permitted to shadow', A.messages[0], "A should have a syntax error reported") def test_untrusted_pipeline_error(self): in_repo_conf = textwrap.dedent( """ - pipeline: name: test """) file_dict = {'.zuul.yaml': in_repo_conf} A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A', files=file_dict) A.addApproval('Code-Review', 2) self.fake_gerrit.addEvent(A.addApproval('Approved', 1)) self.waitUntilSettled() self.assertEqual(A.data['status'], 'NEW') self.assertEqual(A.reported, 1, "A should report failure") self.assertIn('Pipelines may not be defined', A.messages[0], "A should have a syntax error reported") def test_untrusted_project_error(self): in_repo_conf = textwrap.dedent( """ - project: name: org/project1 """) file_dict = {'.zuul.yaml': in_repo_conf} A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A', files=file_dict) A.addApproval('Code-Review', 2) self.fake_gerrit.addEvent(A.addApproval('Approved', 1)) self.waitUntilSettled() self.assertEqual(A.data['status'], 'NEW') self.assertEqual(A.reported, 1, "A should report failure") self.assertIn('the only project definition permitted', A.messages[0], "A should have a syntax error reported") def test_untrusted_depends_on_trusted(self): with open(os.path.join(FIXTURE_DIR, 'config/in-repo/git/', 'common-config/zuul.yaml')) as f: common_config = f.read() common_config += textwrap.dedent( """ - job: name: project-test9 """) file_dict = {'zuul.yaml': common_config} A = self.fake_gerrit.addFakeChange('common-config', 'master', 'A', files=file_dict) in_repo_conf = textwrap.dedent( """ - job: name: project-test1 - project: name: org/project check: jobs: - project-test9 """) file_dict = {'zuul.yaml': in_repo_conf} B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B', files=file_dict) B.data['commitMessage'] = '%s\n\nDepends-On: %s\n' % ( B.subject, A.data['id']) self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1)) self.waitUntilSettled() self.assertEqual(B.data['status'], 'NEW') self.assertEqual(B.reported, 1, "B should report failure") self.assertIn('depends on a change to a config project', B.messages[0], "A should have a syntax error reported") def test_duplicate_node_error(self): in_repo_conf = textwrap.dedent( """ - nodeset: name: duplicate nodes: - name: compute label: foo - name: compute label: foo """) file_dict = {'.zuul.yaml': in_repo_conf} A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A', files=file_dict) A.addApproval('Code-Review', 2) self.fake_gerrit.addEvent(A.addApproval('Approved', 1)) self.waitUntilSettled() self.assertEqual(A.data['status'], 'NEW') self.assertEqual(A.reported, 1, "A should report failure") self.assertIn('appears multiple times', A.messages[0], "A should have a syntax error reported") def test_duplicate_group_error(self): in_repo_conf = textwrap.dedent( """ - nodeset: name: duplicate nodes: - name: compute label: foo groups: - name: group nodes: compute - name: group nodes: compute """) file_dict = {'.zuul.yaml': in_repo_conf} A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A', files=file_dict) A.addApproval('Code-Review', 2) self.fake_gerrit.addEvent(A.addApproval('Approved', 1)) self.waitUntilSettled() self.assertEqual(A.data['status'], 'NEW') self.assertEqual(A.reported, 1, "A should report failure") self.assertIn('appears multiple times', A.messages[0], "A should have a syntax error reported") def test_secret_not_found_error(self): in_repo_conf = textwrap.dedent( """ - job: name: project-test1 run: playbooks/project-test1.yaml secrets: does-not-exist """) file_dict = {'.zuul.yaml': in_repo_conf} A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A', files=file_dict) A.addApproval('Code-Review', 2) self.fake_gerrit.addEvent(A.addApproval('Approved', 1)) self.waitUntilSettled() self.assertEqual(A.data['status'], 'NEW') self.assertEqual(A.reported, 1, "A should report failure") self.assertIn('secret "does-not-exist" was not found', A.messages[0], "A should have a syntax error reported") def test_nodeset_not_found_error(self): in_repo_conf = textwrap.dedent( """ - job: name: test nodeset: does-not-exist """) file_dict = {'.zuul.yaml': in_repo_conf} A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A', files=file_dict) A.addApproval('Code-Review', 2) self.fake_gerrit.addEvent(A.addApproval('Approved', 1)) self.waitUntilSettled() self.assertEqual(A.data['status'], 'NEW') self.assertEqual(A.reported, 1, "A should report failure") self.assertIn('nodeset "does-not-exist" was not found', A.messages[0], "A should have a syntax error reported") def test_required_project_not_found_error(self): in_repo_conf = textwrap.dedent( """ - job: name: project-test1 - job: name: test required-projects: - does-not-exist """) file_dict = {'.zuul.yaml': in_repo_conf} A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A', files=file_dict) A.addApproval('Code-Review', 2) self.fake_gerrit.addEvent(A.addApproval('Approved', 1)) self.waitUntilSettled() self.assertEqual(A.data['status'], 'NEW') self.assertEqual(A.reported, 1, "A should report failure") self.assertIn('Unknown project does-not-exist', A.messages[0], "A should have a syntax error reported") def test_template_not_found_error(self): in_repo_conf = textwrap.dedent( """ - job: name: project-test1 - project: name: org/project templates: - does-not-exist """) file_dict = {'.zuul.yaml': in_repo_conf} A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A', files=file_dict) A.addApproval('Code-Review', 2) self.fake_gerrit.addEvent(A.addApproval('Approved', 1)) self.waitUntilSettled() self.assertEqual(A.data['status'], 'NEW') self.assertEqual(A.reported, 1, "A should report failure") self.assertIn('project template "does-not-exist" was not found', A.messages[0], "A should have a syntax error reported") def test_job_list_in_project_template_not_dict_error(self): in_repo_conf = textwrap.dedent( """ - job: name: project-test1 - project-template: name: some-jobs check: jobs: - project-test1: - required-projects: org/project2 """) file_dict = {'.zuul.yaml': in_repo_conf} A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A', files=file_dict) A.addApproval('Code-Review', 2) self.fake_gerrit.addEvent(A.addApproval('Approved', 1)) self.waitUntilSettled() self.assertEqual(A.data['status'], 'NEW') self.assertEqual(A.reported, 1, "A should report failure") self.assertIn('expected str for dictionary value', A.messages[0], "A should have a syntax error reported") def test_job_list_in_project_not_dict_error(self): in_repo_conf = textwrap.dedent( """ - job: name: project-test1 - project: name: org/project1 check: jobs: - project-test1: - required-projects: org/project2 """) file_dict = {'.zuul.yaml': in_repo_conf} A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A', files=file_dict) A.addApproval('Code-Review', 2) self.fake_gerrit.addEvent(A.addApproval('Approved', 1)) self.waitUntilSettled() self.assertEqual(A.data['status'], 'NEW') self.assertEqual(A.reported, 1, "A should report failure") self.assertIn('expected str for dictionary value', A.messages[0], "A should have a syntax error reported") def test_project_template(self): # Tests that a project template is not modified when used, and # can therefore be used in subsequent reconfigurations. in_repo_conf = textwrap.dedent( """ - job: name: project-test1 run: playbooks/project-test1.yaml - project-template: name: some-jobs tenant-one-gate: jobs: - project-test1: required-projects: - org/project1 - project: name: org/project templates: - some-jobs """) file_dict = {'.zuul.yaml': in_repo_conf} A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A', files=file_dict) A.addApproval('Code-Review', 2) self.fake_gerrit.addEvent(A.addApproval('Approved', 1)) self.waitUntilSettled() self.assertEqual(A.data['status'], 'MERGED') self.fake_gerrit.addEvent(A.getChangeMergedEvent()) self.waitUntilSettled() in_repo_conf = textwrap.dedent( """ - project: name: org/project1 templates: - some-jobs """) file_dict = {'.zuul.yaml': in_repo_conf} B = self.fake_gerrit.addFakeChange('org/project1', 'master', 'B', files=file_dict) B.addApproval('Code-Review', 2) self.fake_gerrit.addEvent(B.addApproval('Approved', 1)) self.waitUntilSettled() self.assertEqual(B.data['status'], 'MERGED') def test_job_remove_add(self): # Tests that a job can be removed from one repo and added in another. # First, remove the current config for project1 since it # references the job we want to remove. file_dict = {'.zuul.yaml': None} A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A', files=file_dict) A.setMerged() self.fake_gerrit.addEvent(A.getChangeMergedEvent()) self.waitUntilSettled() # Then propose a change to delete the job from one repo... file_dict = {'.zuul.yaml': None} B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B', files=file_dict) self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1)) self.waitUntilSettled() # ...and a second that depends on it that adds it to another repo. in_repo_conf = textwrap.dedent( """ - job: name: project-test1 run: playbooks/project-test1.yaml - project: name: org/project1 check: jobs: - project-test1 """) in_repo_playbook = textwrap.dedent( """ - hosts: all tasks: [] """) file_dict = {'.zuul.yaml': in_repo_conf, 'playbooks/project-test1.yaml': in_repo_playbook} C = self.fake_gerrit.addFakeChange('org/project1', 'master', 'C', files=file_dict, parent='refs/changes/1/1/1') C.data['commitMessage'] = '%s\n\nDepends-On: %s\n' % ( C.subject, B.data['id']) self.fake_gerrit.addEvent(C.getPatchsetCreatedEvent(1)) self.waitUntilSettled() self.assertHistory([ dict(name='project-test1', result='SUCCESS', changes='2,1 3,1'), ], ordered=False) def test_multi_repo(self): downstream_repo_conf = textwrap.dedent( """ - project: name: org/project1 tenant-one-gate: jobs: - project-test1 - job: name: project1-test1 parent: project-test1 """) file_dict = {'.zuul.yaml': downstream_repo_conf} A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A', files=file_dict) A.addApproval('Code-Review', 2) self.fake_gerrit.addEvent(A.addApproval('Approved', 1)) self.waitUntilSettled() self.assertEqual(A.data['status'], 'MERGED') self.fake_gerrit.addEvent(A.getChangeMergedEvent()) self.waitUntilSettled() upstream_repo_conf = textwrap.dedent( """ - job: name: project-test1 run: playbooks/project-test1.yaml - job: name: project-test2 - project: name: org/project tenant-one-gate: jobs: - project-test1 """) file_dict = {'.zuul.yaml': upstream_repo_conf} B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B', files=file_dict) B.addApproval('Code-Review', 2) self.fake_gerrit.addEvent(B.addApproval('Approved', 1)) self.waitUntilSettled() self.assertEqual(B.data['status'], 'MERGED') self.fake_gerrit.addEvent(B.getChangeMergedEvent()) self.waitUntilSettled() tenant = self.sched.abide.tenants.get('tenant-one') # Ensure the latest change is reflected in the config; if it # isn't this will raise an exception. tenant.layout.getJob('project-test2') def test_pipeline_error(self): with open(os.path.join(FIXTURE_DIR, 'config/in-repo/git/', 'common-config/zuul.yaml')) as f: base_common_config = f.read() in_repo_conf_A = textwrap.dedent( """ - pipeline: name: periodic foo: error """) file_dict = {'zuul.yaml': None, 'zuul.d/main.yaml': base_common_config, 'zuul.d/test1.yaml': in_repo_conf_A} A = self.fake_gerrit.addFakeChange('common-config', 'master', 'A', files=file_dict) self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1)) self.waitUntilSettled() self.assertEqual(A.reported, 1, "A should report failure") self.assertIn('syntax error', A.messages[0], "A should have an error reported") def test_change_series_error(self): with open(os.path.join(FIXTURE_DIR, 'config/in-repo/git/', 'common-config/zuul.yaml')) as f: base_common_config = f.read() in_repo_conf_A = textwrap.dedent( """ - pipeline: name: periodic foo: error """) file_dict = {'zuul.yaml': None, 'zuul.d/main.yaml': base_common_config, 'zuul.d/test1.yaml': in_repo_conf_A} A = self.fake_gerrit.addFakeChange('common-config', 'master', 'A', files=file_dict) in_repo_conf_B = textwrap.dedent( """ - job: name: project-test2 foo: error """) file_dict = {'zuul.yaml': None, 'zuul.d/main.yaml': base_common_config, 'zuul.d/test1.yaml': in_repo_conf_A, 'zuul.d/test2.yaml': in_repo_conf_B} B = self.fake_gerrit.addFakeChange('common-config', 'master', 'B', files=file_dict) B.setDependsOn(A, 1) C = self.fake_gerrit.addFakeChange('common-config', 'master', 'C') C.setDependsOn(B, 1) self.fake_gerrit.addEvent(C.getPatchsetCreatedEvent(1)) self.waitUntilSettled() self.assertEqual(C.reported, 1, "C should report failure") self.assertIn('Zuul encountered a syntax error while parsing ' 'its configuration', C.messages[0], "C should have an error reported") def test_pipeline_debug(self): in_repo_conf = textwrap.dedent( """ - job: name: project-test1 run: playbooks/project-test1.yaml - project: name: org/project check: debug: True jobs: - project-test1 """) file_dict = {'.zuul.yaml': in_repo_conf} A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A', files=file_dict) self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1)) self.waitUntilSettled() self.assertEqual(A.data['status'], 'NEW') self.assertEqual(A.reported, 1, "A should report success") self.assertIn('Debug information:', A.messages[0], "A should have debug info") class TestJobContamination(AnsibleZuulTestCase): config_file = 'zuul-connections-gerrit-and-github.conf' tenant_config_file = 'config/zuul-job-contamination/main.yaml' def test_job_contamination_playbooks(self): conf = textwrap.dedent( """ - job: name: base post-run: - playbooks/something-new.yaml parent: null vars: basevar: basejob """) file_dict = {'zuul.d/jobs.yaml': conf} A = self.fake_github.openFakePullRequest( 'org/global-config', 'master', 'A', files=file_dict) self.fake_github.emitEvent(A.getPullRequestOpenedEvent()) self.waitUntilSettled() B = self.fake_github.openFakePullRequest('org/project1', 'master', 'A') self.fake_github.emitEvent(B.getPullRequestOpenedEvent()) self.waitUntilSettled() statuses_b = self.fake_github.getCommitStatuses( 'org/project1', B.head_sha) self.assertEqual(len(statuses_b), 1) # B should not be affected by the A PR self.assertEqual('success', statuses_b[0]['state']) def test_job_contamination_vars(self): conf = textwrap.dedent( """ - job: name: base parent: null vars: basevar: basejob-modified """) file_dict = {'zuul.d/jobs.yaml': conf} A = self.fake_github.openFakePullRequest( 'org/global-config', 'master', 'A', files=file_dict) self.fake_github.emitEvent(A.getPullRequestOpenedEvent()) self.waitUntilSettled() B = self.fake_github.openFakePullRequest('org/project1', 'master', 'A') self.fake_github.emitEvent(B.getPullRequestOpenedEvent()) self.waitUntilSettled() statuses_b = self.fake_github.getCommitStatuses( 'org/project1', B.head_sha) self.assertEqual(len(statuses_b), 1) # B should not be affected by the A PR self.assertEqual('success', statuses_b[0]['state']) class TestInRepoJoin(ZuulTestCase): # In this config, org/project is not a member of any pipelines, so # that we may test the changes that cause it to join them. tenant_config_file = 'config/in-repo-join/main.yaml' def test_dynamic_dependent_pipeline(self): # Test dynamically adding a project to a # dependent pipeline for the first time self.executor_server.hold_jobs_in_build = True tenant = self.sched.abide.tenants.get('tenant-one') gate_pipeline = tenant.layout.pipelines['gate'] self.assertEqual(gate_pipeline.queues, []) in_repo_conf = textwrap.dedent( """ - job: name: project-test1 run: playbooks/project-test1.yaml - job: name: project-test2 run: playbooks/project-test2.yaml - project: name: org/project gate: jobs: - project-test2 """) in_repo_playbook = textwrap.dedent( """ - hosts: all tasks: [] """) file_dict = {'.zuul.yaml': in_repo_conf, 'playbooks/project-test2.yaml': in_repo_playbook} A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A', files=file_dict) A.addApproval('Code-Review', 2) self.fake_gerrit.addEvent(A.addApproval('Approved', 1)) self.waitUntilSettled() items = gate_pipeline.getAllItems() self.assertEqual(items[0].change.number, '1') self.assertEqual(items[0].change.patchset, '1') self.assertTrue(items[0].live) self.executor_server.hold_jobs_in_build = False self.executor_server.release() self.waitUntilSettled() # Make sure the dynamic queue got cleaned up self.assertEqual(gate_pipeline.queues, []) def test_dynamic_dependent_pipeline_failure(self): # Test that a change behind a failing change adding a project # to a dependent pipeline is dequeued. self.executor_server.hold_jobs_in_build = True in_repo_conf = textwrap.dedent( """ - job: name: project-test1 run: playbooks/project-test1.yaml - project: name: org/project gate: jobs: - project-test1 """) file_dict = {'.zuul.yaml': in_repo_conf} A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A', files=file_dict) self.executor_server.failJob('project-test1', A) A.addApproval('Code-Review', 2) self.fake_gerrit.addEvent(A.addApproval('Approved', 1)) self.waitUntilSettled() B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B') B.addApproval('Code-Review', 2) self.fake_gerrit.addEvent(B.addApproval('Approved', 1)) self.waitUntilSettled() self.orderedRelease() self.waitUntilSettled() self.assertEqual(A.reported, 2, "A should report start and failure") self.assertEqual(A.data['status'], 'NEW') self.assertEqual(B.reported, 1, "B should report start") self.assertHistory([ dict(name='project-test1', result='FAILURE', changes='1,1'), dict(name='project-test1', result='ABORTED', changes='1,1 2,1'), ], ordered=False) def test_dynamic_dependent_pipeline_absent(self): # Test that a series of dependent changes don't report merge # failures to a pipeline they aren't in. A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A') B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B') B.setDependsOn(A, 1) A.addApproval('Code-Review', 2) A.addApproval('Approved', 1) B.addApproval('Code-Review', 2) self.fake_gerrit.addEvent(B.addApproval('Approved', 1)) self.waitUntilSettled() self.assertEqual(A.reported, 0, "A should not report") self.assertEqual(A.data['status'], 'NEW') self.assertEqual(B.reported, 0, "B should not report") self.assertEqual(B.data['status'], 'NEW') self.assertHistory([]) class TestAnsible(AnsibleZuulTestCase): # A temporary class to hold new tests while others are disabled tenant_config_file = 'config/ansible/main.yaml' def test_playbook(self): # This test runs a bit long and needs extra time. self.wait_timeout = 120 # Keep the jobdir around so we can inspect contents if an # assert fails. self.executor_server.keep_jobdir = True # Output extra ansible info so we might see errors. self.executor_server.verbose = True # Add a site variables file, used by check-vars path = os.path.join(FIXTURE_DIR, 'config', 'ansible', 'variables.yaml') self.config.set('executor', 'variables', path) A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A') self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1)) self.waitUntilSettled() build_timeout = self.getJobFromHistory('timeout') with self.jobLog(build_timeout): self.assertEqual(build_timeout.result, 'TIMED_OUT') post_flag_path = os.path.join(self.test_root, build_timeout.uuid + '.post.flag') self.assertTrue(os.path.exists(post_flag_path)) build_post_timeout = self.getJobFromHistory('post-timeout') with self.jobLog(build_post_timeout): self.assertEqual(build_post_timeout.result, 'POST_FAILURE') build_faillocal = self.getJobFromHistory('faillocal') with self.jobLog(build_faillocal): self.assertEqual(build_faillocal.result, 'FAILURE') build_failpost = self.getJobFromHistory('failpost') with self.jobLog(build_failpost): self.assertEqual(build_failpost.result, 'POST_FAILURE') build_check_vars = self.getJobFromHistory('check-vars') with self.jobLog(build_check_vars): self.assertEqual(build_check_vars.result, 'SUCCESS') build_check_hostvars = self.getJobFromHistory('check-hostvars') with self.jobLog(build_check_hostvars): self.assertEqual(build_check_hostvars.result, 'SUCCESS') build_check_secret_names = self.getJobFromHistory('check-secret-names') with self.jobLog(build_check_secret_names): self.assertEqual(build_check_secret_names.result, 'SUCCESS') build_hello = self.getJobFromHistory('hello-world') with self.jobLog(build_hello): self.assertEqual(build_hello.result, 'SUCCESS') build_python27 = self.getJobFromHistory('python27') with self.jobLog(build_python27): self.assertEqual(build_python27.result, 'SUCCESS') flag_path = os.path.join(self.test_root, build_python27.uuid + '.flag') self.assertTrue(os.path.exists(flag_path)) copied_path = os.path.join(self.test_root, build_python27.uuid + '.copied') self.assertTrue(os.path.exists(copied_path)) failed_path = os.path.join(self.test_root, build_python27.uuid + '.failed') self.assertFalse(os.path.exists(failed_path)) pre_flag_path = os.path.join(self.test_root, build_python27.uuid + '.pre.flag') self.assertTrue(os.path.exists(pre_flag_path)) post_flag_path = os.path.join(self.test_root, build_python27.uuid + '.post.flag') self.assertTrue(os.path.exists(post_flag_path)) bare_role_flag_path = os.path.join(self.test_root, build_python27.uuid + '.bare-role.flag') self.assertTrue(os.path.exists(bare_role_flag_path)) secrets_path = os.path.join(self.test_root, build_python27.uuid + '.secrets') with open(secrets_path) as f: self.assertEqual(f.read(), "test-username test-password") msg = A.messages[0] success = "{} https://success.example.com/zuul-logs/{}" fail = "{} https://failure.example.com/zuul-logs/{}" self.assertIn(success.format("python27", build_python27.uuid), msg) self.assertIn(fail.format("faillocal", build_faillocal.uuid), msg) self.assertIn(success.format("check-vars", build_check_vars.uuid), msg) self.assertIn(success.format("hello-world", build_hello.uuid), msg) self.assertIn(fail.format("timeout", build_timeout.uuid), msg) self.assertIn(fail.format("failpost", build_failpost.uuid), msg) def test_repo_ansible(self): A = self.fake_gerrit.addFakeChange('org/ansible', 'master', 'A') self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1)) self.waitUntilSettled() self.assertEqual(A.reported, 1, "A should report success") self.assertHistory([ dict(name='hello-ansible', result='SUCCESS', changes='1,1'), ]) def _add_job(self, job_name): conf = textwrap.dedent( """ - job: name: %s run: playbooks/%s.yaml - project: name: org/plugin-project check: jobs: - %s """ % (job_name, job_name, job_name)) file_dict = {'.zuul.yaml': conf} A = self.fake_gerrit.addFakeChange('org/plugin-project', 'master', 'A', files=file_dict) self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1)) self.waitUntilSettled() def test_plugins(self): # Keep the jobdir around so we can inspect contents if an # assert fails. self.executor_server.keep_jobdir = True # Output extra ansible info so we might see errors. self.executor_server.verbose = True count = 0 plugin_tests = [ ('passwd', 'FAILURE'), ('cartesian', 'SUCCESS'), ('consul_kv', 'FAILURE'), ('credstash', 'FAILURE'), ('csvfile_good', 'SUCCESS'), ('csvfile_bad', 'FAILURE'), ('uri_bad_path', 'FAILURE'), ('uri_bad_scheme', 'FAILURE'), ('block_local_override', 'FAILURE'), ('file_local_good', 'SUCCESS'), ('file_local_bad', 'FAILURE'), ('zuul_return', 'SUCCESS'), ] for job_name, result in plugin_tests: count += 1 self._add_job(job_name) job = self.getJobFromHistory(job_name) with self.jobLog(job): self.assertEqual(count, len(self.history)) build = self.history[-1] self.assertEqual(build.result, result) # TODOv3(jeblair): parse the ansible output and verify we're # getting the exception we expect. class TestPrePlaybooks(AnsibleZuulTestCase): # A temporary class to hold new tests while others are disabled tenant_config_file = 'config/pre-playbook/main.yaml' wait_timeout = 60 def test_pre_playbook_fail(self): # Test that we run the post playbooks (but not the actual # playbook) when a pre-playbook fails. A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A') self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1)) self.waitUntilSettled() build = self.getJobFromHistory('python27') self.assertIsNone(build.result) self.assertIn('RETRY_LIMIT', A.messages[0]) flag_path = os.path.join(self.test_root, build.uuid + '.main.flag') self.assertFalse(os.path.exists(flag_path)) pre_flag_path = os.path.join(self.test_root, build.uuid + '.pre.flag') self.assertFalse(os.path.exists(pre_flag_path)) post_flag_path = os.path.join(self.test_root, build.uuid + '.post.flag') self.assertTrue(os.path.exists(post_flag_path), "The file %s should exist" % post_flag_path) def test_post_playbook_fail_autohold(self): client = zuul.rpcclient.RPCClient('127.0.0.1', self.gearman_server.port) self.addCleanup(client.shutdown) r = client.autohold('tenant-one', 'org/project3', 'python27-node-post', "", "", "reason text", 1) self.assertTrue(r) A = self.fake_gerrit.addFakeChange('org/project3', 'master', 'A') self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1)) self.waitUntilSettled() build = self.getJobFromHistory('python27-node-post') self.assertEqual(build.result, 'POST_FAILURE') # Check nodepool for a held node held_node = None for node in self.fake_nodepool.getNodes(): if node['state'] == zuul.model.STATE_HOLD: held_node = node break self.assertIsNotNone(held_node) # Validate node has recorded the failed job self.assertEqual( held_node['hold_job'], " ".join(['tenant-one', 'review.example.com/org/project3', 'python27-node-post', '.*']) ) self.assertEqual(held_node['comment'], "reason text") def test_pre_playbook_fail_autohold(self): client = zuul.rpcclient.RPCClient('127.0.0.1', self.gearman_server.port) self.addCleanup(client.shutdown) r = client.autohold('tenant-one', 'org/project2', 'python27-node', "", "", "reason text", 1) self.assertTrue(r) A = self.fake_gerrit.addFakeChange('org/project2', 'master', 'A') self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1)) self.waitUntilSettled() build = self.getJobFromHistory('python27-node') self.assertIsNone(build.result) self.assertIn('RETRY_LIMIT', A.messages[0]) # Check nodepool for a held node held_node = None for node in self.fake_nodepool.getNodes(): if node['state'] == zuul.model.STATE_HOLD: held_node = node break self.assertIsNotNone(held_node) # Validate node has recorded the failed job self.assertEqual( held_node['hold_job'], " ".join(['tenant-one', 'review.example.com/org/project2', 'python27-node', '.*']) ) self.assertEqual(held_node['comment'], "reason text") class TestPostPlaybooks(AnsibleZuulTestCase): tenant_config_file = 'config/post-playbook/main.yaml' wait_timeout = 60 def test_post_playbook_abort(self): # Test that when we abort a job in the post playbook, that we # don't send back POST_FAILURE. self.executor_server.verbose = True A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A') self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1)) while not len(self.builds): time.sleep(0.1) build = self.builds[0] post_start = os.path.join(self.test_root, build.uuid + '.post_start.flag') start = time.time() while time.time() < start + 90: if os.path.exists(post_start): break time.sleep(0.1) # The post playbook has started, abort the job self.fake_gerrit.addEvent(A.getChangeAbandonedEvent()) self.waitUntilSettled() build = self.getJobFromHistory('python27') self.assertEqual('ABORTED', build.result) post_end = os.path.join(self.test_root, build.uuid + '.post_end.flag') self.assertTrue(os.path.exists(post_start)) self.assertFalse(os.path.exists(post_end)) class TestBrokenConfig(ZuulTestCase): # Test we can deal with a broken config tenant_config_file = 'config/broken/main.yaml' def test_broken_config_on_startup(self): # verify get the errors at tenant level. tenant = self.sched.abide.tenants.get('tenant-one') self.assertEquals( len(tenant.layout.loading_errors), 1, "An error should have been stored") self.assertIn( "Zuul encountered a syntax error", str(tenant.layout.loading_errors[0].error)) @simple_layout('layouts/broken-template.yaml') def test_broken_config_on_startup_template(self): # Verify that a missing project-template doesn't break gate # pipeline construction. tenant = self.sched.abide.tenants.get('tenant-one') self.assertEquals( len(tenant.layout.loading_errors), 1, "An error should have been stored") self.assertIn( "Zuul encountered a syntax error", str(tenant.layout.loading_errors[0].error)) def test_dynamic_ignore(self): # Verify dynamic config behaviors inside a tenant broken config tenant = self.sched.abide.tenants.get('tenant-one') # There is a configuration error self.assertEquals( len(tenant.layout.loading_errors), 1, "An error should have been stored") # Inside a broken tenant configuration environment, # send a valid config to an "unbroken" project and verify # that tenant configuration have been validated and job executed in_repo_conf = textwrap.dedent( """ - job: name: project-test run: playbooks/project-test.yaml - project: check: jobs: - project-test """) file_dict = {'.zuul.yaml': in_repo_conf} A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A', files=file_dict) self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1)) self.waitUntilSettled() self.assertEqual(A.patchsets[0]['approvals'][0]['value'], "1") self.assertHistory([ dict(name='project-test', result='SUCCESS', changes='1,1')]) def test_dynamic_fail_unbroken(self): # Verify dynamic config behaviors inside a tenant broken config tenant = self.sched.abide.tenants.get('tenant-one') # There is a configuration error self.assertEquals( len(tenant.layout.loading_errors), 1, "An error should have been stored") # Inside a broken tenant configuration environment, # send an invalid config to an "unbroken" project and verify # that tenant configuration have not been validated in_repo_conf = textwrap.dedent( """ - job: name: project-test run: playbooks/project-test.yaml - project: check: jobs: - non-existent-job """) file_dict = {'.zuul.yaml': in_repo_conf} B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B', files=file_dict) self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1)) self.waitUntilSettled() self.assertEqual(B.reported, 1, "A should report failure") self.assertEqual(B.patchsets[0]['approvals'][0]['value'], "-1") self.assertIn('Job non-existent-job not defined', B.messages[0], "A should have failed the check pipeline") def test_dynamic_fail_broken(self): # Verify dynamic config behaviors inside a tenant broken config tenant = self.sched.abide.tenants.get('tenant-one') # There is a configuration error self.assertEquals( len(tenant.layout.loading_errors), 1, "An error should have been stored") # Inside a broken tenant configuration environment, # send an invalid config to a "broken" project and verify # that tenant configuration have not been validated in_repo_conf = textwrap.dedent( """ - job: name: project-test run: playbooks/project-test.yaml - project: check: jobs: - non-existent-job """) file_dict = {'.zuul.yaml': in_repo_conf} C = self.fake_gerrit.addFakeChange('org/project2', 'master', 'C', files=file_dict) self.fake_gerrit.addEvent(C.getPatchsetCreatedEvent(1)) self.waitUntilSettled() self.assertEqual(C.reported, 1, "A should report failure") self.assertEqual(C.patchsets[0]['approvals'][0]['value'], "-1") self.assertIn('Job non-existent-job not defined', C.messages[0], "A should have failed the check pipeline") def test_dynamic_fix_broken(self): # Verify dynamic config behaviors inside a tenant broken config tenant = self.sched.abide.tenants.get('tenant-one') # There is a configuration error self.assertEquals( len(tenant.layout.loading_errors), 1, "An error should have been stored") # Inside a broken tenant configuration environment, # send an valid config to a "broken" project and verify # that tenant configuration have been validated and job executed in_repo_conf = textwrap.dedent( """ - job: name: project-test2 run: playbooks/project-test.yaml - project: check: jobs: - project-test2 """) file_dict = {'.zuul.yaml': in_repo_conf} D = self.fake_gerrit.addFakeChange('org/project2', 'master', 'D', files=file_dict) self.fake_gerrit.addEvent(D.getPatchsetCreatedEvent(1)) self.waitUntilSettled() self.assertEqual(D.patchsets[0]['approvals'][0]['value'], "1") self.assertHistory([ dict(name='project-test2', result='SUCCESS', changes='1,1')]) def test_dynamic_fail_cross_repo(self): # Verify dynamic config behaviors inside a tenant broken config tenant = self.sched.abide.tenants.get('tenant-one') # There is a configuration error self.assertEquals( len(tenant.layout.loading_errors), 1, "An error should have been stored") # Inside a broken tenant configuration environment, remove a # job used in another repo and verify that an error is # reported despite the error being in a repo other than the # change. in_repo_conf = textwrap.dedent( """ - pipeline: name: check manager: independent trigger: gerrit: - event: patchset-created success: gerrit: Verified: 1 failure: gerrit: Verified: -1 - job: name: base parent: null - project: name: common-config check: jobs: - noop """) file_dict = {'zuul.yaml': in_repo_conf} A = self.fake_gerrit.addFakeChange('common-config', 'master', 'A', files=file_dict) self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1)) self.waitUntilSettled() self.assertEqual(A.reported, 1, "A should report failure") self.assertEqual(A.patchsets[0]['approvals'][0]['value'], "-1") self.assertIn('Job central-test not defined', A.messages[0], "A should have failed the check pipeline") class TestProjectKeys(ZuulTestCase): # Test that we can generate project keys # Normally the test infrastructure copies a static key in place # for each project before starting tests. This saves time because # Zuul's automatic key-generation on startup can be slow. To make # sure we exercise that code, in this test we allow Zuul to create # keys for the project on startup. create_project_keys = True config_file = 'zuul-connections-gerrit-and-github.conf' tenant_config_file = 'config/in-repo/main.yaml' def test_key_generation(self): key_root = os.path.join(self.state_root, 'keys') private_key_file = os.path.join(key_root, 'gerrit/org/project.pem') # Make sure that a proper key was created on startup with open(private_key_file, "rb") as f: private_key, public_key = \ encryption.deserialize_rsa_keypair(f.read()) with open(os.path.join(FIXTURE_DIR, 'private.pem')) as i: fixture_private_key = i.read() # Make sure that we didn't just end up with the static fixture # key self.assertNotEqual(fixture_private_key, private_key) # Make sure it's the right length self.assertEqual(4096, private_key.key_size) class RoleTestCase(ZuulTestCase): def _getRolesPaths(self, build, playbook): path = os.path.join(self.test_root, build.uuid, 'ansible', playbook, 'ansible.cfg') roles_paths = [] with open(path) as f: for line in f: if line.startswith('roles_path'): roles_paths.append(line) return roles_paths def _assertRolePath(self, build, playbook, content): roles_paths = self._getRolesPaths(build, playbook) if content: self.assertEqual(len(roles_paths), 1, "Should have one roles_path line in %s" % (playbook,)) self.assertIn(content, roles_paths[0]) else: self.assertEqual(len(roles_paths), 0, "Should have no roles_path line in %s" % (playbook,)) def _assertInRolePath(self, build, playbook, files): roles_paths = self._getRolesPaths(build, playbook)[0] roles_paths = roles_paths.split('=')[-1].strip() roles_paths = roles_paths.split(':') files = set(files) matches = set() for rpath in roles_paths: for rolename in os.listdir(rpath): if rolename in files: matches.add(rolename) self.assertEqual(files, matches) class TestRoleBranches(RoleTestCase): tenant_config_file = 'config/role-branches/main.yaml' def _addRole(self, project, branch, role, parent=None): data = textwrap.dedent(""" - name: %s debug: msg: %s """ % (role, role)) file_dict = {'roles/%s/tasks/main.yaml' % role: data} A = self.fake_gerrit.addFakeChange(project, branch, 'add %s' % role, files=file_dict, parent=parent) A.addApproval('Code-Review', 2) self.fake_gerrit.addEvent(A.addApproval('Approved', 1)) self.waitUntilSettled() self.fake_gerrit.addEvent(A.getChangeMergedEvent()) self.waitUntilSettled() return A.patchsets[-1]['ref'] def _addPlaybook(self, project, branch, playbook, role, parent=None): data = textwrap.dedent(""" - hosts: all roles: - %s """ % role) file_dict = {'playbooks/%s.yaml' % playbook: data} A = self.fake_gerrit.addFakeChange(project, branch, 'add %s' % playbook, files=file_dict, parent=parent) A.addApproval('Code-Review', 2) self.fake_gerrit.addEvent(A.addApproval('Approved', 1)) self.waitUntilSettled() self.fake_gerrit.addEvent(A.getChangeMergedEvent()) self.waitUntilSettled() return A.patchsets[-1]['ref'] def _assertInFile(self, path, content): with open(path) as f: self.assertIn(content, f.read()) def test_playbook_role_branches(self): # This tests that the correct branch of a repo which contains # a playbook or a role is checked out. Most of the action # happens on project1, which holds a parent job, so that we # can test the behavior of a project which is not in the # dependency chain. # First we create some branch-specific content in project1: self.create_branch('project1', 'stable') # A pre-playbook with unique stable branch content. p = self._addPlaybook('project1', 'stable', 'parent-job-pre', 'parent-stable-role') # A role that only exists on the stable branch. self._addRole('project1', 'stable', 'stable-role', parent=p) # The same for the master branch. p = self._addPlaybook('project1', 'master', 'parent-job-pre', 'parent-master-role') self._addRole('project1', 'master', 'master-role', parent=p) self.sched.reconfigure(self.config) # Push a change to project2 which will run 3 jobs which # inherit from project1. self.executor_server.hold_jobs_in_build = True A = self.fake_gerrit.addFakeChange('project2', 'master', 'A') self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1)) self.waitUntilSettled() self.assertEqual(len(self.builds), 3) # This job should use the master branch since that's the # zuul.branch for this change. build = self.getBuildByName('child-job') self._assertInRolePath(build, 'playbook_0', ['master-role']) self._assertInFile(build.jobdir.pre_playbooks[1].path, 'parent-master-role') # The main playbook is on the master branch of project2, but # there is a job-level branch override, so the project1 role # should be from the stable branch. The job-level override # will cause Zuul to select the project1 pre-playbook from the # stable branch as well, so we should see it using the stable # role. build = self.getBuildByName('child-job-override') self._assertInRolePath(build, 'playbook_0', ['stable-role']) self._assertInFile(build.jobdir.pre_playbooks[1].path, 'parent-stable-role') # The same, but using a required-projects override. build = self.getBuildByName('child-job-project-override') self._assertInRolePath(build, 'playbook_0', ['stable-role']) self._assertInFile(build.jobdir.pre_playbooks[1].path, 'parent-stable-role') self.executor_server.hold_jobs_in_build = False self.executor_server.release() self.waitUntilSettled() class TestRoles(RoleTestCase): tenant_config_file = 'config/roles/main.yaml' def test_role(self): # This exercises a proposed change to a role being checked out # and used. A = self.fake_gerrit.addFakeChange('bare-role', 'master', 'A') B = self.fake_gerrit.addFakeChange('org/project', 'master', 'A') B.data['commitMessage'] = '%s\n\nDepends-On: %s\n' % ( B.subject, A.data['id']) self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1)) self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1)) self.waitUntilSettled() self.assertHistory([ dict(name='project-test', result='SUCCESS', changes='1,1 2,1'), ]) def test_role_inheritance(self): self.executor_server.hold_jobs_in_build = True conf = textwrap.dedent( """ - job: name: parent roles: - zuul: bare-role pre-run: playbooks/parent-pre.yaml post-run: playbooks/parent-post.yaml - job: name: project-test parent: parent run: playbooks/project-test.yaml roles: - zuul: org/project - project: name: org/project check: jobs: - project-test """) file_dict = {'.zuul.yaml': conf} A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A', files=file_dict) self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1)) self.waitUntilSettled() self.assertEqual(len(self.builds), 1) build = self.getBuildByName('project-test') self._assertRolePath(build, 'pre_playbook_0', 'role_0') self._assertRolePath(build, 'playbook_0', 'role_0') self._assertRolePath(build, 'playbook_0', 'role_1') self._assertRolePath(build, 'post_playbook_0', 'role_0') self.executor_server.hold_jobs_in_build = False self.executor_server.release() self.waitUntilSettled() self.assertHistory([ dict(name='project-test', result='SUCCESS', changes='1,1'), ]) def test_role_error(self): conf = textwrap.dedent( """ - job: name: project-test run: playbooks/project-test.yaml roles: - zuul: common-config - project: name: org/project check: jobs: - project-test """) file_dict = {'.zuul.yaml': conf} A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A', files=file_dict) self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1)) self.waitUntilSettled() self.assertIn( '- project-test project-test : ERROR Unable to find role', A.messages[-1]) class TestImplicitRoles(RoleTestCase): tenant_config_file = 'config/implicit-roles/main.yaml' def test_missing_roles(self): # Test implicit and explicit roles for a project which does # not have roles. The implicit role should be silently # ignored since the project doesn't supply roles, but if a # user declares an explicit role, it should error. self.executor_server.hold_jobs_in_build = True A = self.fake_gerrit.addFakeChange('org/norole-project', 'master', 'A') self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1)) self.waitUntilSettled() self.assertEqual(len(self.builds), 2) build = self.getBuildByName('implicit-role-fail') self._assertRolePath(build, 'playbook_0', None) self.executor_server.hold_jobs_in_build = False self.executor_server.release() self.waitUntilSettled() # The retry_limit doesn't get recorded self.assertHistory([ dict(name='implicit-role-fail', result='SUCCESS', changes='1,1'), ]) def test_roles(self): # Test implicit and explicit roles for a project which does # have roles. In both cases, we should end up with the role # in the path. In the explicit case, ensure we end up with # the name we specified. self.executor_server.hold_jobs_in_build = True A = self.fake_gerrit.addFakeChange('org/role-project', 'master', 'A') self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1)) self.waitUntilSettled() self.assertEqual(len(self.builds), 2) build = self.getBuildByName('implicit-role-ok') self._assertRolePath(build, 'playbook_0', 'role_0') build = self.getBuildByName('explicit-role-ok') self._assertRolePath(build, 'playbook_0', 'role_0') self.executor_server.hold_jobs_in_build = False self.executor_server.release() self.waitUntilSettled() self.assertHistory([ dict(name='implicit-role-ok', result='SUCCESS', changes='1,1'), dict(name='explicit-role-ok', result='SUCCESS', changes='1,1'), ], ordered=False) class TestShadow(ZuulTestCase): tenant_config_file = 'config/shadow/main.yaml' def test_shadow(self): # Test that a repo is allowed to shadow another's job definitions. A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A') self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1)) self.waitUntilSettled() self.assertHistory([ dict(name='test1', result='SUCCESS', changes='1,1'), dict(name='test2', result='SUCCESS', changes='1,1'), ], ordered=False) class TestDataReturn(AnsibleZuulTestCase): tenant_config_file = 'config/data-return/main.yaml' def test_data_return(self): A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A') self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1)) self.waitUntilSettled() self.assertHistory([ dict(name='data-return', result='SUCCESS', changes='1,1'), dict(name='data-return-relative', result='SUCCESS', changes='1,1'), dict(name='child', result='SUCCESS', changes='1,1'), ], ordered=False) self.assertIn('- data-return http://example.com/test/log/url/', A.messages[-1]) self.assertIn('- data-return-relative ' 'http://example.com/test/log/url/docs/index.html', A.messages[-1]) def test_data_return_child_jobs(self): A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A') self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1)) self.waitUntilSettled() self.assertHistory([ dict(name='data-return-child-jobs', result='SUCCESS', changes='1,1'), dict(name='data-return', result='SUCCESS', changes='1,1'), ]) self.assertIn( '- data-return-child-jobs http://example.com/test/log/url/', A.messages[-1]) self.assertIn( '- data-return http://example.com/test/log/url/', A.messages[-1]) self.assertIn('child : SKIPPED', A.messages[-1]) self.assertIn('Build succeeded', A.messages[-1]) def test_data_return_invalid_child_job(self): A = self.fake_gerrit.addFakeChange('org/project2', 'master', 'A') self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1)) self.waitUntilSettled() self.assertHistory([ dict(name='data-return-invalid-child-job', result='SUCCESS', changes='1,1')]) self.assertIn( '- data-return-invalid-child-job http://example.com/test/log/url/', A.messages[-1]) self.assertIn('data-return : SKIPPED', A.messages[-1]) self.assertIn('Build succeeded', A.messages[-1]) def test_data_return_skip_all_child_jobs(self): A = self.fake_gerrit.addFakeChange('org/project3', 'master', 'A') self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1)) self.waitUntilSettled() self.assertHistory([ dict(name='data-return-skip-all', result='SUCCESS', changes='1,1'), ]) self.assertIn( '- data-return-skip-all http://example.com/test/log/url/', A.messages[-1]) self.assertIn('child : SKIPPED', A.messages[-1]) self.assertIn('data-return : SKIPPED', A.messages[-1]) self.assertIn('Build succeeded', A.messages[-1]) class TestDiskAccounting(AnsibleZuulTestCase): config_file = 'zuul-disk-accounting.conf' tenant_config_file = 'config/disk-accountant/main.yaml' def test_disk_accountant_kills_job(self): A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A') self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1)) self.waitUntilSettled() self.assertHistory([ dict(name='dd-big-empty-file', result='ABORTED', changes='1,1')]) class TestMaxNodesPerJob(AnsibleZuulTestCase): tenant_config_file = 'config/multi-tenant/main.yaml' def test_max_timeout_exceeded(self): in_repo_conf = textwrap.dedent( """ - job: name: test-job nodeset: nodes: - name: node01 label: fake - name: node02 label: fake - name: node03 label: fake - name: node04 label: fake - name: node05 label: fake - name: node06 label: fake """) file_dict = {'.zuul.yaml': in_repo_conf} A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A', files=file_dict) self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1)) self.waitUntilSettled() self.assertIn('The job "test-job" exceeds tenant max-nodes-per-job 5.', A.messages[0], "A should fail because of nodes limit") B = self.fake_gerrit.addFakeChange('org/project2', 'master', 'A', files=file_dict) self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1)) self.waitUntilSettled() self.assertNotIn("exceeds tenant max-nodes", B.messages[0], "B should not fail because of nodes limit") class TestMaxTimeout(ZuulTestCase): tenant_config_file = 'config/multi-tenant/main.yaml' def test_max_nodes_reached(self): in_repo_conf = textwrap.dedent( """ - job: name: test-job timeout: 3600 """) file_dict = {'.zuul.yaml': in_repo_conf} A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A', files=file_dict) self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1)) self.waitUntilSettled() self.assertIn('The job "test-job" exceeds tenant max-job-timeout', A.messages[0], "A should fail because of timeout limit") B = self.fake_gerrit.addFakeChange('org/project2', 'master', 'A', files=file_dict) self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1)) self.waitUntilSettled() self.assertNotIn("exceeds tenant max-job-timeout", B.messages[0], "B should not fail because of timeout limit") class TestPragma(ZuulTestCase): tenant_config_file = 'config/pragma/main.yaml' def test_no_pragma(self): self.create_branch('org/project', 'stable') with open(os.path.join(FIXTURE_DIR, 'config/pragma/git/', 'org_project/nopragma.yaml')) as f: config = f.read() file_dict = {'.zuul.yaml': config} A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A', files=file_dict) A.addApproval('Code-Review', 2) self.fake_gerrit.addEvent(A.addApproval('Approved', 1)) self.waitUntilSettled() self.fake_gerrit.addEvent(A.getChangeMergedEvent()) self.waitUntilSettled() # This is an untrusted repo with 2 branches, so it should have # an implied branch matcher for the job. tenant = self.sched.abide.tenants.get('tenant-one') jobs = tenant.layout.getJobs('test-job') self.assertEqual(len(jobs), 1) for job in tenant.layout.getJobs('test-job'): self.assertIsNotNone(job.branch_matcher) def test_pragma(self): self.create_branch('org/project', 'stable') with open(os.path.join(FIXTURE_DIR, 'config/pragma/git/', 'org_project/pragma.yaml')) as f: config = f.read() file_dict = {'.zuul.yaml': config} A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A', files=file_dict) A.addApproval('Code-Review', 2) self.fake_gerrit.addEvent(A.addApproval('Approved', 1)) self.waitUntilSettled() self.fake_gerrit.addEvent(A.getChangeMergedEvent()) self.waitUntilSettled() # This is an untrusted repo with 2 branches, so it would # normally have an implied branch matcher, but our pragma # overrides it. tenant = self.sched.abide.tenants.get('tenant-one') jobs = tenant.layout.getJobs('test-job') self.assertEqual(len(jobs), 1) for job in tenant.layout.getJobs('test-job'): self.assertIsNone(job.branch_matcher) class TestPragmaMultibranch(ZuulTestCase): tenant_config_file = 'config/pragma-multibranch/main.yaml' def test_no_branch_matchers(self): self.create_branch('org/project1', 'stable/pike') self.create_branch('org/project2', 'stable/jewel') self.fake_gerrit.addEvent( self.fake_gerrit.getFakeBranchCreatedEvent( 'org/project1', 'stable/pike')) self.fake_gerrit.addEvent( self.fake_gerrit.getFakeBranchCreatedEvent( 'org/project2', 'stable/jewel')) self.waitUntilSettled() # We want the jobs defined on the stable/pike branch of # project1 to apply to the stable/jewel branch of project2. # First, without the pragma line, the jobs should not run # because in project1 they have branch matchers for pike, so # they will not match a jewel change. B = self.fake_gerrit.addFakeChange('org/project2', 'stable/jewel', 'B') self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1)) self.waitUntilSettled() self.assertHistory([]) # Add a pragma line to disable implied branch matchers in # project1, so that the jobs and templates apply to both # branches. with open(os.path.join(FIXTURE_DIR, 'config/pragma-multibranch/git/', 'org_project1/zuul.yaml')) as f: config = f.read() extra_conf = textwrap.dedent( """ - pragma: implied-branch-matchers: False """) config = extra_conf + config file_dict = {'zuul.yaml': config} A = self.fake_gerrit.addFakeChange('org/project1', 'stable/pike', 'A', files=file_dict) A.addApproval('Code-Review', 2) self.fake_gerrit.addEvent(A.addApproval('Approved', 1)) self.waitUntilSettled() self.fake_gerrit.addEvent(A.getChangeMergedEvent()) self.waitUntilSettled() # Now verify that when we propose a change to jewel, we get # the pike/jewel jobs. self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1)) self.waitUntilSettled() self.assertHistory([ dict(name='test-job1', result='SUCCESS', changes='1,1'), dict(name='test-job2', result='SUCCESS', changes='1,1'), ], ordered=False) def test_supplied_branch_matchers(self): self.create_branch('org/project1', 'stable/pike') self.create_branch('org/project2', 'stable/jewel') self.fake_gerrit.addEvent( self.fake_gerrit.getFakeBranchCreatedEvent( 'org/project1', 'stable/pike')) self.fake_gerrit.addEvent( self.fake_gerrit.getFakeBranchCreatedEvent( 'org/project2', 'stable/jewel')) self.waitUntilSettled() # We want the jobs defined on the stable/pike branch of # project1 to apply to the stable/jewel branch of project2. # First, without the pragma line, the jobs should not run # because in project1 they have branch matchers for pike, so # they will not match a jewel change. B = self.fake_gerrit.addFakeChange('org/project2', 'stable/jewel', 'B') self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1)) self.waitUntilSettled() self.assertHistory([]) # Add a pragma line to disable implied branch matchers in # project1, so that the jobs and templates apply to both # branches. with open(os.path.join(FIXTURE_DIR, 'config/pragma-multibranch/git/', 'org_project1/zuul.yaml')) as f: config = f.read() extra_conf = textwrap.dedent( """ - pragma: implied-branches: - stable/pike - stable/jewel """) config = extra_conf + config file_dict = {'zuul.yaml': config} A = self.fake_gerrit.addFakeChange('org/project1', 'stable/pike', 'A', files=file_dict) A.addApproval('Code-Review', 2) self.fake_gerrit.addEvent(A.addApproval('Approved', 1)) self.waitUntilSettled() self.fake_gerrit.addEvent(A.getChangeMergedEvent()) self.waitUntilSettled() # Now verify that when we propose a change to jewel, we get # the pike/jewel jobs. self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1)) self.waitUntilSettled() self.assertHistory([ dict(name='test-job1', result='SUCCESS', changes='1,1'), dict(name='test-job2', result='SUCCESS', changes='1,1'), ], ordered=False) class TestBaseJobs(ZuulTestCase): tenant_config_file = 'config/base-jobs/main.yaml' def test_multiple_base_jobs(self): A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A') self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1)) self.waitUntilSettled() self.assertHistory([ dict(name='my-job', result='SUCCESS', changes='1,1'), dict(name='other-job', result='SUCCESS', changes='1,1'), ], ordered=False) self.assertEqual(self.getJobFromHistory('my-job'). parameters['zuul']['jobtags'], ['mybase']) self.assertEqual(self.getJobFromHistory('other-job'). parameters['zuul']['jobtags'], ['otherbase']) def test_untrusted_base_job(self): """Test that a base job may not be defined in an untrusted repo""" in_repo_conf = textwrap.dedent( """ - job: name: fail-base parent: null """) file_dict = {'.zuul.yaml': in_repo_conf} A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A', files=file_dict) self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1)) self.waitUntilSettled() self.assertEqual(A.reported, 1, "A should report failure") self.assertEqual(A.patchsets[0]['approvals'][0]['value'], "-1") self.assertIn('Base jobs must be defined in config projects', A.messages[0]) self.assertHistory([]) class TestSecrets(ZuulTestCase): tenant_config_file = 'config/secrets/main.yaml' secret = {'password': 'test-password', 'username': 'test-username'} def _getSecrets(self, job, pbtype): secrets = [] build = self.getJobFromHistory(job) for pb in build.parameters[pbtype]: secrets.append(pb['secrets']) return secrets def test_secret_branch(self): # Test that we can use a secret defined in another branch of # the same project. self.create_branch('org/project2', 'stable') self.fake_gerrit.addEvent( self.fake_gerrit.getFakeBranchCreatedEvent( 'org/project2', 'stable')) self.waitUntilSettled() with open(os.path.join(FIXTURE_DIR, 'config/secrets/git/', 'org_project2/zuul-secret.yaml')) as f: config = f.read() file_dict = {'zuul.yaml': config} A = self.fake_gerrit.addFakeChange('org/project2', 'master', 'A', files=file_dict) A.addApproval('Code-Review', 2) self.fake_gerrit.addEvent(A.addApproval('Approved', 1)) self.waitUntilSettled() self.assertEqual(A.data['status'], 'MERGED') self.fake_gerrit.addEvent(A.getChangeMergedEvent()) self.waitUntilSettled() in_repo_conf = textwrap.dedent( """ - job: parent: base name: project2-secret run: playbooks/secret.yaml secrets: [project2_secret] - project: check: jobs: - project2-secret gate: jobs: - noop """) file_dict = {'zuul.yaml': in_repo_conf} B = self.fake_gerrit.addFakeChange('org/project2', 'stable', 'B', files=file_dict) self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1)) self.waitUntilSettled() self.assertEqual(B.reported, 1, "B should report success") self.assertHistory([ dict(name='project2-secret', result='SUCCESS', changes='2,1'), ]) self.assertEqual( self._getSecrets('project2-secret', 'playbooks'), [{'project2_secret': self.secret}]) def test_secret_branch_duplicate(self): # Test that we can create a duplicate secret on a different # branch of the same project -- i.e., that when we branch # master to stable on a project with a secret, nothing # changes. self.create_branch('org/project1', 'stable') self.fake_gerrit.addEvent( self.fake_gerrit.getFakeBranchCreatedEvent( 'org/project1', 'stable')) self.waitUntilSettled() A = self.fake_gerrit.addFakeChange('org/project1', 'stable', 'A') self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1)) self.waitUntilSettled() self.assertEqual(A.reported, 1, "A should report success") self.assertHistory([ dict(name='project1-secret', result='SUCCESS', changes='1,1'), ]) self.assertEqual( self._getSecrets('project1-secret', 'playbooks'), [{'project1_secret': self.secret}]) def test_secret_branch_error_same_branch(self): # Test that we are unable to define a secret twice on the same # project-branch. in_repo_conf = textwrap.dedent( """ - secret: name: project1_secret data: {} - secret: name: project1_secret data: {} """) file_dict = {'zuul.yaml': in_repo_conf} A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A', files=file_dict) self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1)) self.waitUntilSettled() self.assertIn('already defined', A.messages[0]) def test_secret_branch_error_same_project(self): # Test that we are unable to create a secret which differs # from another with the same name -- i.e., that if we have a # duplicate secret on multiple branches of the same project, # they must be identical. self.create_branch('org/project1', 'stable') self.fake_gerrit.addEvent( self.fake_gerrit.getFakeBranchCreatedEvent( 'org/project1', 'stable')) self.waitUntilSettled() in_repo_conf = textwrap.dedent( """ - secret: name: project1_secret data: {} """) file_dict = {'zuul.yaml': in_repo_conf} A = self.fake_gerrit.addFakeChange('org/project1', 'stable', 'A', files=file_dict) self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1)) self.waitUntilSettled() self.assertIn('does not match existing definition in branch master', A.messages[0]) def test_secret_branch_error_other_project(self): # Test that we are unable to create a secret with the same # name as another. We're never allowed to have a secret with # the same name outside of a project. in_repo_conf = textwrap.dedent( """ - secret: name: project1_secret data: {} """) file_dict = {'zuul.yaml': in_repo_conf} A = self.fake_gerrit.addFakeChange('org/project2', 'master', 'A', files=file_dict) self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1)) self.waitUntilSettled() self.assertIn('already defined in project org/project1', A.messages[0]) class TestSecretInheritance(ZuulTestCase): tenant_config_file = 'config/secret-inheritance/main.yaml' def _getSecrets(self, job, pbtype): secrets = [] build = self.getJobFromHistory(job) for pb in build.parameters[pbtype]: secrets.append(pb['secrets']) return secrets def _checkTrustedSecrets(self): secret = {'longpassword': 'test-passwordtest-password', 'password': 'test-password', 'username': 'test-username'} base_secret = {'username': 'base-username'} self.assertEqual( self._getSecrets('trusted-secrets', 'playbooks'), [{'trusted-secret': secret}]) self.assertEqual( self._getSecrets('trusted-secrets', 'pre_playbooks'), [{'base-secret': base_secret}]) self.assertEqual( self._getSecrets('trusted-secrets', 'post_playbooks'), []) self.assertEqual( self._getSecrets('trusted-secrets-trusted-child', 'playbooks'), [{}]) self.assertEqual( self._getSecrets('trusted-secrets-trusted-child', 'pre_playbooks'), [{'base-secret': base_secret}]) self.assertEqual( self._getSecrets('trusted-secrets-trusted-child', 'post_playbooks'), []) self.assertEqual( self._getSecrets('trusted-secrets-untrusted-child', 'playbooks'), [{}]) self.assertEqual( self._getSecrets('trusted-secrets-untrusted-child', 'pre_playbooks'), [{'base-secret': base_secret}]) self.assertEqual( self._getSecrets('trusted-secrets-untrusted-child', 'post_playbooks'), []) def _checkUntrustedSecrets(self): secret = {'longpassword': 'test-passwordtest-password', 'password': 'test-password', 'username': 'test-username'} base_secret = {'username': 'base-username'} self.assertEqual( self._getSecrets('untrusted-secrets', 'playbooks'), [{'untrusted-secret': secret}]) self.assertEqual( self._getSecrets('untrusted-secrets', 'pre_playbooks'), [{'base-secret': base_secret}]) self.assertEqual( self._getSecrets('untrusted-secrets', 'post_playbooks'), []) self.assertEqual( self._getSecrets('untrusted-secrets-trusted-child', 'playbooks'), [{}]) self.assertEqual( self._getSecrets('untrusted-secrets-trusted-child', 'pre_playbooks'), [{'base-secret': base_secret}]) self.assertEqual( self._getSecrets('untrusted-secrets-trusted-child', 'post_playbooks'), []) self.assertEqual( self._getSecrets('untrusted-secrets-untrusted-child', 'playbooks'), [{}]) self.assertEqual( self._getSecrets('untrusted-secrets-untrusted-child', 'pre_playbooks'), [{'base-secret': base_secret}]) self.assertEqual( self._getSecrets('untrusted-secrets-untrusted-child', 'post_playbooks'), []) def test_trusted_secret_inheritance_check(self): A = self.fake_gerrit.addFakeChange('common-config', 'master', 'A') self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1)) self.waitUntilSettled() self.assertHistory([ dict(name='trusted-secrets', result='SUCCESS', changes='1,1'), dict(name='trusted-secrets-trusted-child', result='SUCCESS', changes='1,1'), dict(name='trusted-secrets-untrusted-child', result='SUCCESS', changes='1,1'), ], ordered=False) self._checkTrustedSecrets() def test_untrusted_secret_inheritance_gate(self): A = self.fake_gerrit.addFakeChange('common-config', 'master', 'A') A.addApproval('Code-Review', 2) self.fake_gerrit.addEvent(A.addApproval('Approved', 1)) self.waitUntilSettled() self.assertHistory([ dict(name='untrusted-secrets', result='SUCCESS', changes='1,1'), dict(name='untrusted-secrets-trusted-child', result='SUCCESS', changes='1,1'), dict(name='untrusted-secrets-untrusted-child', result='SUCCESS', changes='1,1'), ], ordered=False) self._checkUntrustedSecrets() def test_untrusted_secret_inheritance_check(self): A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A') self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1)) self.waitUntilSettled() # This configuration tries to run untrusted secrets in an # non-post-review pipeline and should therefore run no jobs. self.assertHistory([]) class TestSecretLeaks(AnsibleZuulTestCase): tenant_config_file = 'config/secret-leaks/main.yaml' def searchForContent(self, path, content): matches = [] for (dirpath, dirnames, filenames) in os.walk(path): for filename in filenames: filepath = os.path.join(dirpath, filename) with open(filepath, 'rb') as f: if content in f.read(): matches.append(filepath[len(path):]) return matches def _test_secret_file(self): # Or rather -- test that they *don't* leak. # Keep the jobdir around so we can inspect contents. self.executor_server.keep_jobdir = True conf = textwrap.dedent( """ - project: name: org/project check: jobs: - secret-file """) file_dict = {'.zuul.yaml': conf} A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A', files=file_dict) self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1)) self.waitUntilSettled() self.assertHistory([ dict(name='secret-file', result='SUCCESS', changes='1,1'), ], ordered=False) matches = self.searchForContent(self.history[0].jobdir.root, b'test-password') self.assertEqual(set(['/work/secret-file.txt']), set(matches)) def test_secret_file(self): self._test_secret_file() def test_secret_file_verbose(self): # Output extra ansible info to exercise alternate logging code # paths. self.executor_server.verbose = True self._test_secret_file() def _test_secret_file_fail(self): # Or rather -- test that they *don't* leak. # Keep the jobdir around so we can inspect contents. self.executor_server.keep_jobdir = True conf = textwrap.dedent( """ - project: name: org/project check: jobs: - secret-file-fail """) file_dict = {'.zuul.yaml': conf} A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A', files=file_dict) self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1)) self.waitUntilSettled() self.assertHistory([ dict(name='secret-file-fail', result='FAILURE', changes='1,1'), ], ordered=False) matches = self.searchForContent(self.history[0].jobdir.root, b'test-password') self.assertEqual(set(['/work/failure-file.txt']), set(matches)) def test_secret_file_fail(self): self._test_secret_file_fail() def test_secret_file_fail_verbose(self): # Output extra ansible info to exercise alternate logging code # paths. self.executor_server.verbose = True self._test_secret_file_fail() class TestNodesets(ZuulTestCase): tenant_config_file = 'config/nodesets/main.yaml' def test_nodeset_branch(self): # Test that we can use a nodeset defined in another branch of # the same project. self.create_branch('org/project2', 'stable') self.fake_gerrit.addEvent( self.fake_gerrit.getFakeBranchCreatedEvent( 'org/project2', 'stable')) self.waitUntilSettled() with open(os.path.join(FIXTURE_DIR, 'config/nodesets/git/', 'org_project2/zuul-nodeset.yaml')) as f: config = f.read() file_dict = {'zuul.yaml': config} A = self.fake_gerrit.addFakeChange('org/project2', 'master', 'A', files=file_dict) A.addApproval('Code-Review', 2) self.fake_gerrit.addEvent(A.addApproval('Approved', 1)) self.waitUntilSettled() self.assertEqual(A.data['status'], 'MERGED') self.fake_gerrit.addEvent(A.getChangeMergedEvent()) self.waitUntilSettled() in_repo_conf = textwrap.dedent( """ - job: parent: base name: project2-test nodeset: project2-nodeset - project: check: jobs: - project2-test gate: jobs: - noop """) file_dict = {'zuul.yaml': in_repo_conf} B = self.fake_gerrit.addFakeChange('org/project2', 'stable', 'B', files=file_dict) self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1)) self.waitUntilSettled() self.assertEqual(B.reported, 1, "B should report success") self.assertHistory([ dict(name='project2-test', result='SUCCESS', changes='2,1', node='ubuntu-xenial'), ]) def test_nodeset_branch_duplicate(self): # Test that we can create a duplicate nodeset on a different # branch of the same project -- i.e., that when we branch # master to stable on a project with a nodeset, nothing # changes. self.create_branch('org/project1', 'stable') self.fake_gerrit.addEvent( self.fake_gerrit.getFakeBranchCreatedEvent( 'org/project1', 'stable')) self.waitUntilSettled() A = self.fake_gerrit.addFakeChange('org/project1', 'stable', 'A') self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1)) self.waitUntilSettled() self.assertEqual(A.reported, 1, "A should report success") self.assertHistory([ dict(name='project1-test', result='SUCCESS', changes='1,1', node='ubuntu-xenial'), ]) def test_nodeset_branch_error_same_branch(self): # Test that we are unable to define a nodeset twice on the same # project-branch. in_repo_conf = textwrap.dedent( """ - nodeset: name: project1-nodeset nodes: [] - nodeset: name: project1-nodeset nodes: [] """) file_dict = {'zuul.yaml': in_repo_conf} A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A', files=file_dict) self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1)) self.waitUntilSettled() self.assertIn('already defined', A.messages[0]) def test_nodeset_branch_error_same_project(self): # Test that we are unable to create a nodeset which differs # from another with the same name -- i.e., that if we have a # duplicate nodeset on multiple branches of the same project, # they must be identical. self.create_branch('org/project1', 'stable') self.fake_gerrit.addEvent( self.fake_gerrit.getFakeBranchCreatedEvent( 'org/project1', 'stable')) self.waitUntilSettled() in_repo_conf = textwrap.dedent( """ - nodeset: name: project1-nodeset nodes: [] """) file_dict = {'zuul.yaml': in_repo_conf} A = self.fake_gerrit.addFakeChange('org/project1', 'stable', 'A', files=file_dict) self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1)) self.waitUntilSettled() self.assertIn('does not match existing definition in branch master', A.messages[0]) def test_nodeset_branch_error_other_project(self): # Test that we are unable to create a nodeset with the same # name as another. We're never allowed to have a nodeset with # the same name outside of a project. in_repo_conf = textwrap.dedent( """ - nodeset: name: project1-nodeset nodes: [] """) file_dict = {'zuul.yaml': in_repo_conf} A = self.fake_gerrit.addFakeChange('org/project2', 'master', 'A', files=file_dict) self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1)) self.waitUntilSettled() self.assertIn('already defined in project org/project1', A.messages[0]) class TestSemaphoreBranches(ZuulTestCase): tenant_config_file = 'config/semaphore-branches/main.yaml' def test_semaphore_branch(self): # Test that we can use a semaphore defined in another branch of # the same project. self.create_branch('org/project2', 'stable') self.fake_gerrit.addEvent( self.fake_gerrit.getFakeBranchCreatedEvent( 'org/project2', 'stable')) self.waitUntilSettled() with open(os.path.join(FIXTURE_DIR, 'config/semaphore-branches/git/', 'org_project2/zuul-semaphore.yaml')) as f: config = f.read() file_dict = {'zuul.yaml': config} A = self.fake_gerrit.addFakeChange('org/project2', 'master', 'A', files=file_dict) A.addApproval('Code-Review', 2) self.fake_gerrit.addEvent(A.addApproval('Approved', 1)) self.waitUntilSettled() self.assertEqual(A.data['status'], 'MERGED') self.fake_gerrit.addEvent(A.getChangeMergedEvent()) self.waitUntilSettled() in_repo_conf = textwrap.dedent( """ - job: parent: base name: project2-test semaphore: project2-semaphore - project: check: jobs: - project2-test gate: jobs: - noop """) file_dict = {'zuul.yaml': in_repo_conf} B = self.fake_gerrit.addFakeChange('org/project2', 'stable', 'B', files=file_dict) self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1)) self.waitUntilSettled() self.assertEqual(B.reported, 1, "B should report success") self.assertHistory([ dict(name='project2-test', result='SUCCESS', changes='2,1') ]) def test_semaphore_branch_duplicate(self): # Test that we can create a duplicate semaphore on a different # branch of the same project -- i.e., that when we branch # master to stable on a project with a semaphore, nothing # changes. self.create_branch('org/project1', 'stable') self.fake_gerrit.addEvent( self.fake_gerrit.getFakeBranchCreatedEvent( 'org/project1', 'stable')) self.waitUntilSettled() A = self.fake_gerrit.addFakeChange('org/project1', 'stable', 'A') self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1)) self.waitUntilSettled() self.assertEqual(A.reported, 1, "A should report success") self.assertHistory([ dict(name='project1-test', result='SUCCESS', changes='1,1') ]) def test_semaphore_branch_error_same_branch(self): # Test that we are unable to define a semaphore twice on the same # project-branch. in_repo_conf = textwrap.dedent( """ - semaphore: name: project1-semaphore max: 2 - semaphore: name: project1-semaphore max: 2 """) file_dict = {'zuul.yaml': in_repo_conf} A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A', files=file_dict) self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1)) self.waitUntilSettled() self.assertIn('already defined', A.messages[0]) def test_semaphore_branch_error_same_project(self): # Test that we are unable to create a semaphore which differs # from another with the same name -- i.e., that if we have a # duplicate semaphore on multiple branches of the same project, # they must be identical. self.create_branch('org/project1', 'stable') self.fake_gerrit.addEvent( self.fake_gerrit.getFakeBranchCreatedEvent( 'org/project1', 'stable')) self.waitUntilSettled() in_repo_conf = textwrap.dedent( """ - semaphore: name: project1-semaphore max: 4 """) file_dict = {'zuul.yaml': in_repo_conf} A = self.fake_gerrit.addFakeChange('org/project1', 'stable', 'A', files=file_dict) self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1)) self.waitUntilSettled() self.assertIn('does not match existing definition in branch master', A.messages[0]) def test_semaphore_branch_error_other_project(self): # Test that we are unable to create a semaphore with the same # name as another. We're never allowed to have a semaphore with # the same name outside of a project. in_repo_conf = textwrap.dedent( """ - semaphore: name: project1-semaphore max: 2 """) file_dict = {'zuul.yaml': in_repo_conf} A = self.fake_gerrit.addFakeChange('org/project2', 'master', 'A', files=file_dict) self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1)) self.waitUntilSettled() self.assertIn('already defined in project org/project1', A.messages[0]) class TestJobOutput(AnsibleZuulTestCase): tenant_config_file = 'config/job-output/main.yaml' def _get_file(self, build, path): p = os.path.join(build.jobdir.root, path) with open(p) as f: return f.read() def test_job_output(self): # Verify that command standard output appears in the job output, # and that failures in the final playbook get logged. # This currently only verifies we receive output from # localhost. Notably, it does not verify we receive output # via zuul_console streaming. self.executor_server.keep_jobdir = True A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A') self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1)) self.waitUntilSettled() self.assertHistory([ dict(name='job-output', result='SUCCESS', changes='1,1'), ], ordered=False) token = 'Standard output test %s' % (self.history[0].jobdir.src_root) j = json.loads(self._get_file(self.history[0], 'work/logs/job-output.json')) self.assertEqual(token, j[0]['plays'][0]['tasks'][0] ['hosts']['localhost']['stdout']) self.log.info(self._get_file(self.history[0], 'work/logs/job-output.txt')) self.assertIn(token, self._get_file(self.history[0], 'work/logs/job-output.txt')) def test_job_output_failure_log(self): logger = logging.getLogger('zuul.AnsibleJob') output = io.StringIO() logger.addHandler(logging.StreamHandler(output)) # Verify that a failure in the last post playbook emits the contents # of the json output to the log self.executor_server.keep_jobdir = True A = self.fake_gerrit.addFakeChange('org/project2', 'master', 'A') self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1)) self.waitUntilSettled() self.assertHistory([ dict(name='job-output-failure', result='POST_FAILURE', changes='1,1'), ], ordered=False) token = 'Standard output test %s' % (self.history[0].jobdir.src_root) j = json.loads(self._get_file(self.history[0], 'work/logs/job-output.json')) self.assertEqual(token, j[0]['plays'][0]['tasks'][0] ['hosts']['localhost']['stdout']) self.log.info(self._get_file(self.history[0], 'work/logs/job-output.json')) self.assertIn(token, self._get_file(self.history[0], 'work/logs/job-output.txt')) log_output = output.getvalue() self.assertIn('Final playbook failed', log_output) self.assertIn('Failure test', log_output) class TestPlugins(AnsibleZuulTestCase): tenant_config_file = 'config/speculative-plugins/main.yaml' def _run_job(self, job_name, project='org/project', roles=''): # Output extra ansible info so we might see errors. self.executor_server.verbose = True conf = textwrap.dedent( """ - job: name: {job_name} run: playbooks/{job_name}/test.yaml nodeset: nodes: - name: controller label: whatever {roles} - project: check: jobs: - {job_name} """.format(job_name=job_name, roles=roles)) file_dict = {'zuul.yaml': conf} A = self.fake_gerrit.addFakeChange(project, 'master', 'A', files=file_dict) self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1)) self.waitUntilSettled() message = A.messages[0] self.assertIn('ERROR Ansible plugin dir', message) self.assertIn('found adjacent to playbook', message) self.assertIn('in non-trusted repo', message) def test_filter_plugin(self): self._run_job('filter-plugin-playbook') self._run_job('filter-plugin-playbook-symlink') self._run_job('filter-plugin-bare-role') self._run_job('filter-plugin-role') self._run_job('filter-plugin-repo-role', project='org/projectrole') self._run_job('filter-plugin-shared-role', roles="roles: [{zuul: 'org/project2'}]") self._run_job('filter-plugin-shared-bare-role', roles="roles: [{zuul: 'org/project3', name: 'shared'}]") class TestNoLog(AnsibleZuulTestCase): tenant_config_file = 'config/ansible-no-log/main.yaml' def _get_file(self, build, path): p = os.path.join(build.jobdir.root, path) with open(p) as f: return f.read() def test_no_log_unreachable(self): # Output extra ansible info so we might see errors. self.executor_server.verbose = True self.executor_server.keep_jobdir = True A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A') self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1)) self.waitUntilSettled() json_log = self._get_file(self.history[0], 'work/logs/job-output.json') text_log = self._get_file(self.history[0], 'work/logs/job-output.txt') self.assertNotIn('my-very-secret-password-1', json_log) self.assertNotIn('my-very-secret-password-2', json_log) self.assertNotIn('my-very-secret-password-1', text_log) self.assertNotIn('my-very-secret-password-2', text_log)