summaryrefslogtreecommitdiff
path: root/tests/unit/test_v3.py
diff options
context:
space:
mode:
Diffstat (limited to 'tests/unit/test_v3.py')
-rw-r--r--tests/unit/test_v3.py626
1 files changed, 459 insertions, 167 deletions
diff --git a/tests/unit/test_v3.py b/tests/unit/test_v3.py
index 23c78b3ef..fe5b46e0c 100644
--- a/tests/unit/test_v3.py
+++ b/tests/unit/test_v3.py
@@ -25,12 +25,14 @@ from time import sleep
from unittest import skip, skipIf
from zuul.lib import yamlutil
+import fixtures
import git
import paramiko
import zuul.configloader
from zuul.lib import yamlutil as yaml
from zuul.model import MergeRequest
+from zuul.zk.blob_store import BlobStore
from tests.base import (
AnsibleZuulTestCase,
@@ -865,6 +867,62 @@ class TestBranchMismatch(ZuulTestCase):
dict(name='project-test2', result='SUCCESS', changes='1,1'),
], ordered=False)
+ def test_implied_branch_matcher_regex(self):
+ # Test that branch names that look like regexes aren't treated
+ # as such for implied branch matchers.
+
+ # Make sure the parent job repo is branched, so it gets
+ # implied branch matchers.
+
+ # The '+' in the branch name would cause the change not to
+ # match if it is treated as a regex.
+ self.create_branch('org/project1', 'feature/foo-0.1.12+bar')
+ self.fake_gerrit.addEvent(
+ self.fake_gerrit.getFakeBranchCreatedEvent(
+ 'org/project1', 'feature/foo-0.1.12+bar'))
+
+ A = self.fake_gerrit.addFakeChange(
+ 'org/project1', 'feature/foo-0.1.12+bar', 'A')
+ self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
+ self.waitUntilSettled()
+
+ self.assertHistory([
+ dict(name='project-test1', result='SUCCESS', changes='1,1'),
+ ], ordered=False)
+
+ def test_implied_branch_matcher_pragma_syntax_error(self):
+ # Test that syntax errors are reported if the implied branch
+ # matcher pragma is set. This catches potential errors when
+ # serializing configuration errors since the pragma causes
+ # extra information to be added to the error source context.
+ self.create_branch('org/project1', 'feature/test')
+ self.fake_gerrit.addEvent(
+ self.fake_gerrit.getFakeBranchCreatedEvent(
+ 'org/project1', 'feature/test'))
+
+ in_repo_conf = textwrap.dedent(
+ """
+ - job:
+ name: project-test1
+ nodeset: bar
+ - pragma:
+ implied-branches:
+ - master
+ - feature/r1
+ """)
+ 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.assertHistory([])
+ self.assertEqual(A.data['status'], 'NEW')
+ self.assertEqual(A.reported, 1,
+ "A should report failure")
+ self.assertIn('nodeset "bar" was not found', A.messages[0],
+ "A should have a syntax error reported")
+
class TestBranchRef(ZuulTestCase):
tenant_config_file = 'config/branch-ref/main.yaml'
@@ -1421,6 +1479,38 @@ class TestInRepoConfig(ZuulTestCase):
"A should have failed the check pipeline")
self.assertHistory([])
+ def test_dynamic_nonexistent_job_dependency(self):
+ # Tests that a reference to a nonexistent job dependency is an
+ # error.
+ in_repo_conf = textwrap.dedent(
+ """
+ - job:
+ name: project-test1
+ run: playbooks/project-test1.yaml
+
+ - project:
+ name: org/project
+ check:
+ jobs:
+ - project-test1:
+ dependencies:
+ - name: non-existent-job
+ soft: true
+ """)
+
+ 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('Job non-existent-job not defined', A.messages[0],
+ "A should have failed the check pipeline")
+ self.assertNotIn('freezing', A.messages[0])
+ self.assertHistory([])
+
def test_dynamic_config_new_patchset(self):
self.executor_server.hold_jobs_in_build = True
@@ -1692,6 +1782,25 @@ class TestInRepoConfig(ZuulTestCase):
self.assertIn('while constructing a mapping', A.messages[0],
"A should have a syntax error reported")
+ def test_yaml_dict_error3(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('is 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(
"""
@@ -2573,6 +2682,69 @@ class TestInRepoConfig(ZuulTestCase):
self.assertIn('Debug information:',
A.messages[0], "A should have debug info")
+ def test_nodeset_alternates_cycle(self):
+ in_repo_conf = textwrap.dedent(
+ """
+ - nodeset:
+ name: red
+ alternatives: [blue]
+ - nodeset:
+ name: blue
+ alternatives: [red]
+ - job:
+ name: project-test1
+ run: playbooks/project-test1.yaml
+ nodeset: blue
+ """)
+
+ 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.assertIn("cycle detected", A.messages[0])
+
+ def test_nodeset_alternates_missing_from_nodeset(self):
+ in_repo_conf = textwrap.dedent(
+ """
+ - nodeset:
+ name: red
+ alternatives: [blue]
+ - job:
+ name: project-test1
+ run: playbooks/project-test1.yaml
+ """)
+
+ 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.assertIn('nodeset "blue" was not found', A.messages[0])
+
+ def test_nodeset_alternates_missing_from_job(self):
+ in_repo_conf = textwrap.dedent(
+ """
+ - job:
+ name: project-test1
+ run: playbooks/project-test1.yaml
+ nodeset:
+ alternatives: [red]
+ """)
+
+ 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.assertIn('nodeset "red" was not found', A.messages[0])
+
@skipIfMultiScheduler()
# See comment in TestInRepoConfigDir.scheduler_count for further
# details.
@@ -2880,6 +3052,41 @@ class TestInRepoConfigDir(ZuulTestCase):
], ordered=True)
+class TestExtraConfigInDependent(ZuulTestCase):
+ # in org/project2, jobs are defined in extra config paths, while
+ # project is defined in .zuul.yaml
+ tenant_config_file = 'config/in-repo-dir/main.yaml'
+ scheduler_count = 1
+
+ def test_extra_config_in_dependent_change(self):
+ # Test that when jobs are defined in a extra-config-paths in a repo, if
+ # another change is dependent on a change of that repo, the jobs should
+ # still be loaded.
+
+ # Add an empty zuul.yaml here so we are triggering dynamic layout load
+ A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
+ files={'zuul.yaml': ''})
+ B = self.fake_gerrit.addFakeChange('org/project2', 'master', 'B',
+ files={'zuul.yaml': ''})
+ # A Depends-On: B who has private jobs defined in extra-config-paths
+ A.data['commitMessage'] = '%s\n\nDepends-On: %s\n' % (
+ A.subject, B.data['url'])
+
+ self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
+ self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
+ self.waitUntilSettled()
+
+ # Jobs in both changes should be success
+ self.assertHistory([
+ dict(name='project2-private-extra-file', result='SUCCESS',
+ changes='2,1'),
+ dict(name='project2-private-extra-dir', result='SUCCESS',
+ changes='2,1'),
+ dict(name='project-test1', result='SUCCESS',
+ changes='2,1 1,1'),
+ ], ordered=False)
+
+
class TestGlobalRepoState(AnsibleZuulTestCase):
config_file = 'zuul-connections-gerrit-and-github.conf'
tenant_config_file = 'config/global-repo-state/main.yaml'
@@ -3589,9 +3796,9 @@ class TestInRepoJoin(ZuulTestCase):
class FunctionalAnsibleMixIn(object):
# A temporary class to hold new tests while others are disabled
+ # These should be overridden in child classes.
tenant_config_file = 'config/ansible/main.yaml'
- # This should be overriden in child classes.
- ansible_version = '2.9'
+ ansible_major_minor = 'X.Y'
def test_playbook(self):
# This test runs a bit long and needs extra time.
@@ -3677,8 +3884,12 @@ class FunctionalAnsibleMixIn(object):
build_python27.uuid + '.secrets')
with open(secrets_path) as f:
self.assertEqual(f.read(), "test-username test-password")
+ build_bubblewrap = self.getJobFromHistory('bubblewrap')
+ with self.jobLog(build_bubblewrap):
+ self.assertEqual(build_bubblewrap.result, 'SUCCESS')
def test_repo_ansible(self):
+ self.executor_server.keep_jobdir = True
A = self.fake_gerrit.addFakeChange('org/ansible', 'master', 'A')
self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
self.waitUntilSettled()
@@ -3688,103 +3899,21 @@ class FunctionalAnsibleMixIn(object):
self.assertHistory([
dict(name='hello-ansible', result='SUCCESS', changes='1,1'),
])
+ build = self.getJobFromHistory('hello-ansible', result='SUCCESS')
+ with open(build.jobdir.job_output_file) as f:
+ output = f.read()
+ self.assertIn(f'Ansible version={self.ansible_major_minor}',
+ output)
- def _add_job(self, job_name):
- conf = textwrap.dedent(
- """
- - job:
- name: {job_name}
- run: playbooks/{job_name}.yaml
- ansible-version: {ansible_version}
-
- - project:
- check:
- jobs:
- - {job_name}
- """.format(job_name=job_name,
- ansible_version=self.ansible_version))
-
- 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))
- def _test_plugins(self, plugin_tests):
- # This test runs a bit long and needs extra time.
- self.wait_timeout = 180
+class TestAnsible5(AnsibleZuulTestCase, FunctionalAnsibleMixIn):
+ tenant_config_file = 'config/ansible/main5.yaml'
+ ansible_major_minor = '2.12'
- # 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
-
- # Kick off all test jobs in parallel
- for job_name, result in plugin_tests:
- count += 1
- self._add_job(job_name)
- # Wait for all jobs to complete
- self.waitUntilSettled()
-
- # Check the correct number of jobs ran
- self.assertEqual(count, len(self.history))
- # Check the job results
- for job_name, result in plugin_tests:
- build = self.getJobFromHistory(job_name)
- with self.jobLog(build):
- self.assertEqual(build.result, result)
-
- # TODOv3(jeblair): parse the ansible output and verify we're
- # getting the exception we expect.
-
- def test_plugins_1(self):
- '''
- Split plugin tests to avoid timeouts and exceeding subunit
- report lengths.
- '''
- 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'),
- ]
- self._test_plugins(plugin_tests)
-
- def test_plugins_2(self):
- '''
- Split plugin tests to avoid timeouts and exceeding subunit
- report lengths.
- '''
- plugin_tests = [
- ('block_local_override', 'FAILURE'),
- ('file_local_good', 'SUCCESS'),
- ('file_local_bad', 'FAILURE'),
- ('fileglob_local_good', 'SUCCESS'),
- ('fileglob_local_bad', 'FAILURE'),
- ('find_local_good', 'SUCCESS'),
- ('find_local_bad', 'FAILURE'),
- ('zuul_return', 'SUCCESS'),
- ('password_create_good', 'SUCCESS'),
- ('password_null_good', 'SUCCESS'),
- ('password_read_good', 'SUCCESS'),
- ('password_create_bad', 'FAILURE'),
- ('password_read_bad', 'FAILURE'),
- ]
- self._test_plugins(plugin_tests)
-
-
-class TestAnsible28(AnsibleZuulTestCase, FunctionalAnsibleMixIn):
- ansible_version = '2.8'
-
-
-class TestAnsible29(AnsibleZuulTestCase, FunctionalAnsibleMixIn):
- ansible_version = '2.9'
+class TestAnsible6(AnsibleZuulTestCase, FunctionalAnsibleMixIn):
+ tenant_config_file = 'config/ansible/main6.yaml'
+ ansible_major_minor = '2.13'
class TestPrePlaybooks(AnsibleZuulTestCase):
@@ -4868,7 +4997,7 @@ class TestDataReturn(AnsibleZuulTestCase):
self.assertIn(
'- data-return https://zuul.example.com/',
A.messages[-1])
- self.assertTrue(re.search('child .* SKIPPED', A.messages[-1]))
+ self.assertTrue('Skipped 1 job' in A.messages[-1])
self.assertIn('Build succeeded', A.messages[-1])
def test_data_return_invalid_child_job(self):
@@ -4881,7 +5010,7 @@ class TestDataReturn(AnsibleZuulTestCase):
self.assertIn(
'- data-return-invalid-child-job https://zuul.example.com',
A.messages[-1])
- self.assertTrue(re.search('data-return .* SKIPPED', A.messages[-1]))
+ self.assertTrue('Skipped 1 job' in A.messages[-1])
self.assertIn('Build succeeded', A.messages[-1])
def test_data_return_skip_all_child_jobs(self):
@@ -4895,8 +5024,7 @@ class TestDataReturn(AnsibleZuulTestCase):
self.assertIn(
'- data-return-skip-all https://zuul.example.com/',
A.messages[-1])
- self.assertTrue(re.search('child .* SKIPPED', A.messages[-1]))
- self.assertTrue(re.search('data-return .* SKIPPED', A.messages[-1]))
+ self.assertTrue('Skipped 2 jobs' in A.messages[-1])
self.assertIn('Build succeeded', A.messages[-1])
def test_data_return_skip_all_child_jobs_with_soft_dependencies(self):
@@ -4910,8 +5038,7 @@ class TestDataReturn(AnsibleZuulTestCase):
])
self.assertIn('- data-return-cd https://zuul.example.com/',
A.messages[-1])
- self.assertTrue(re.search('data-return-a .* SKIPPED', A.messages[-1]))
- self.assertTrue(re.search('data-return-b .* SKIPPED', A.messages[-1]))
+ self.assertTrue('Skipped 2 jobs' in A.messages[-1])
self.assertIn('Build succeeded', A.messages[-1])
def test_several_zuul_return(self):
@@ -4925,9 +5052,22 @@ class TestDataReturn(AnsibleZuulTestCase):
self.assertIn(
'- several-zuul-return-child https://zuul.example.com/',
A.messages[-1])
- self.assertTrue(re.search('data-return .* SKIPPED', A.messages[-1]))
+ self.assertTrue('Skipped 1 job' in A.messages[-1])
self.assertIn('Build succeeded', A.messages[-1])
+ def test_data_return_skip_retry(self):
+ A = self.fake_gerrit.addFakeChange(
+ 'org/project-skip-retry',
+ 'master',
+ 'A'
+ )
+ self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
+ self.waitUntilSettled()
+ self.assertHistory([
+ dict(name='skip-retry-return', result='FAILURE',
+ changes='1,1'),
+ ])
+
def test_data_return_child_jobs_failure(self):
A = self.fake_gerrit.addFakeChange('org/project5', 'master', 'A')
self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
@@ -5587,6 +5727,39 @@ class TestSecrets(ZuulTestCase):
self._getSecrets('project2-complex', 'playbooks'),
[secret])
+ def test_blobstore_secret(self):
+ # Test the large secret blob store
+ self.executor_server.hold_jobs_in_build = True
+ self.useFixture(fixtures.MonkeyPatch(
+ 'zuul.model.Job.SECRET_BLOB_SIZE',
+ 1))
+
+ A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
+ self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
+ self.waitUntilSettled()
+
+ context = self.scheds.first.sched.createZKContext(None, self.log)
+ bs = BlobStore(context)
+ self.assertEqual(len(bs), 1)
+
+ self.scheds.first.sched._runBlobStoreCleanup()
+ self.assertEqual(len(bs), 1)
+
+ self.executor_server.hold_jobs_in_build = False
+ self.executor_server.release()
+ self.waitUntilSettled()
+
+ self.assertEqual(A.reported, 1, "A should report success")
+ self.assertHistory([
+ dict(name='project1-secret', result='SUCCESS', changes='1,1'),
+ ])
+ self.assertEqual(
+ [{'secret_name': self.secret}],
+ self._getSecrets('project1-secret', 'playbooks'))
+
+ self.scheds.first.sched._runBlobStoreCleanup()
+ self.assertEqual(len(bs), 0)
+
class TestSecretInheritance(ZuulTestCase):
tenant_config_file = 'config/secret-inheritance/main.yaml'
@@ -6395,68 +6568,21 @@ class TestJobOutput(AnsibleZuulTestCase):
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)
+ def test_job_POST_FAILURE_reports_statsd(self):
+ """Test that POST_FAILURES output job stats."""
+ self.statsd.clear()
+ A = self.fake_gerrit.addFakeChange('org/project2', 'master', 'A')
self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
self.waitUntilSettled()
- return A
-
- def _check_job(self, job_name, project='org/project', roles=''):
- A = self._run_job(job_name, project, roles)
-
- 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._check_job('filter-plugin-playbook')
- self._check_job('filter-plugin-playbook-symlink')
- self._check_job('filter-plugin-bare-role')
- self._check_job('filter-plugin-role')
- self._check_job('filter-plugin-repo-role', project='org/projectrole',
- roles="roles: [{zuul: 'org/projectrole'}]")
- self._check_job('filter-plugin-shared-role',
- roles="roles: [{zuul: 'org/project2'}]")
- self._check_job(
- 'filter-plugin-shared-bare-role',
- roles="roles: [{zuul: 'org/project3', name: 'shared'}]")
-
- def test_implicit_role_not_added(self):
- # This fails because the job uses the role which isn't added
- # to the role path, but it's a normal ansible failure, not a
- # Zuul executor error.
- A = self._run_job('filter-plugin-repo-role', project='org/projectrole')
self.assertHistory([
- dict(name='filter-plugin-repo-role', result='FAILURE',
- changes='1,1'),
+ dict(name='job-output-failure',
+ result='POST_FAILURE', changes='1,1'),
], ordered=False)
- message = A.messages[0]
- self.assertNotIn('Ansible plugin', message)
+ post_failure_stat = 'zuul.tenant.tenant-one.pipeline.check.project.' \
+ 'review_example_com.org_project2.master.job.' \
+ 'job-output-failure.POST_FAILURE'
+ self.assertReportedStat(post_failure_stat, value='1', kind='c')
+ self.assertReportedStat(post_failure_stat, kind='ms')
class TestNoLog(AnsibleZuulTestCase):
@@ -6486,6 +6612,51 @@ class TestNoLog(AnsibleZuulTestCase):
self.assertNotIn('my-very-secret-password-2', text_log)
+class TestJsonStringResults(AnsibleZuulTestCase):
+ tenant_config_file = 'config/ansible-json-string-results/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_ansible_json_string_results(self):
+ """Test modules that return string results are captured
+
+ The yum/dnf modules are seemily almost unique in setting
+ "results" in their module return value to a list of strings
+ (other things might too, but not many other built-in
+ components). Confusingly, when using loops in ansible the
+ output also has a "results" which is a list of dicts with
+ return values from each iteration.
+
+ The zuul_json callback handler needs to deal with both; We've
+ broken this before making changes to its results parsing.
+ This test fakes some string return values like the yum modules
+ do, and ensures they are captured.
+
+ """
+
+ 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.assertIn('if you see this string, it is working', json_log)
+ # Note the text log doesn't include the detail of the returned
+ # results, just the msg field, hence to following "not in"
+ self.assertNotIn('if you see this string, it is working', text_log)
+ self.assertIn('A plugin message', text_log)
+ # no_log checking
+ self.assertNotIn('this is a secret string', json_log)
+ self.assertNotIn('this is a secret string', text_log)
+
+
class TestUnreachable(AnsibleZuulTestCase):
tenant_config_file = 'config/ansible-unreachable/main.yaml'
@@ -6799,7 +6970,7 @@ class TestJobPause(AnsibleZuulTestCase):
dict(name='compile', result='SUCCESS', changes='1,1'),
])
- self.assertTrue(re.search('test .* SKIPPED', A.messages[0]))
+ self.assertTrue('Skipped 1 job' in A.messages[0])
def test_job_pause_pre_skipped_child(self):
"""
@@ -6847,7 +7018,7 @@ class TestJobPause(AnsibleZuulTestCase):
dict(name='compile', result='SUCCESS', changes='1,1'),
])
- self.assertTrue(re.search('test .* SKIPPED', A.messages[0]))
+ self.assertTrue('Skipped 1 job' in A.messages[0])
def test_job_pause_skipped_child_retry(self):
"""
@@ -7716,7 +7887,7 @@ class TestProvidesRequiresMysql(ZuulTestCase):
dict(name='image-builder', result='FAILURE', changes='1,1'),
dict(name='hold', result='SUCCESS', changes='1,1'),
], ordered=False)
- self.assertTrue(re.search('image-user .* SKIPPED', A.messages[0]))
+ self.assertTrue('Skipped 1 job' in A.messages[0])
B = self.fake_gerrit.addFakeChange('org/project1', 'master', 'B')
B.data['commitMessage'] = '%s\n\nDepends-On: %s\n' % (
@@ -7835,8 +8006,8 @@ class TestAnsibleVersion(AnsibleZuulTestCase):
self.assertHistory([
dict(name='ansible-default', result='SUCCESS', changes='1,1'),
- dict(name='ansible-28', result='SUCCESS', changes='1,1'),
- dict(name='ansible-29', result='SUCCESS', changes='1,1'),
+ dict(name='ansible-5', result='SUCCESS', changes='1,1'),
+ dict(name='ansible-6', result='SUCCESS', changes='1,1'),
], ordered=False)
@@ -7855,8 +8026,8 @@ class TestDefaultAnsibleVersion(AnsibleZuulTestCase):
self.assertHistory([
dict(name='ansible-default-zuul-conf', result='SUCCESS',
changes='1,1'),
- dict(name='ansible-28', result='SUCCESS', changes='1,1'),
- dict(name='ansible-29', result='SUCCESS', changes='1,1'),
+ dict(name='ansible-5', result='SUCCESS', changes='1,1'),
+ dict(name='ansible-6', result='SUCCESS', changes='1,1'),
], ordered=False)
@@ -7988,3 +8159,124 @@ class TestConnectionVars(AnsibleZuulTestCase):
# job_output = self._get_file(job, 'work/logs/job-output.txt')
# self.log.debug(job_output)
# self.assertNotIn("/bin/du", job_output)
+
+
+class IncludeBranchesTestCase(ZuulTestCase):
+ def _test_include_branches(self, history1, history2, history3, history4):
+ self.create_branch('org/project', 'stable')
+ self.create_branch('org/project', 'feature/foo')
+ self.fake_gerrit.addEvent(
+ self.fake_gerrit.getFakeBranchCreatedEvent(
+ 'org/project', 'stable'))
+ self.fake_gerrit.addEvent(
+ self.fake_gerrit.getFakeBranchCreatedEvent(
+ 'org/project', 'feature/foo'))
+ self.waitUntilSettled()
+
+ # Test the jobs on the master branch.
+ A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
+ self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
+ self.waitUntilSettled()
+
+ self.assertHistory(history1, ordered=False)
+
+ # Test the jobs on the excluded feature branch.
+ B = self.fake_gerrit.addFakeChange('org/project', 'feature/foo', 'A')
+ self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
+ self.waitUntilSettled()
+
+ self.assertHistory(history1 + history2, ordered=False)
+
+ # Test in-repo config proposed on the excluded feature branch.
+ conf = textwrap.dedent(
+ """
+ - job:
+ name: project-dynamic
+
+ - project:
+ check:
+ jobs:
+ - project-dynamic
+ """)
+ file_dict = {'zuul.yaml': conf}
+ C = self.fake_gerrit.addFakeChange('org/project', 'feature/foo', 'A',
+ files=file_dict)
+ self.fake_gerrit.addEvent(C.getPatchsetCreatedEvent(1))
+ self.waitUntilSettled()
+
+ self.assertHistory(history1 + history2 + history3, ordered=False)
+
+ old = self.scheds.first.sched.tenant_layout_state.get('tenant-one')
+ # Merge a change to the excluded feature branch.
+ B.addApproval('Code-Review', 2)
+ self.fake_gerrit.addEvent(B.addApproval('Approved', 1))
+ self.waitUntilSettled()
+ self.assertEqual(B.data['status'], 'MERGED')
+ self.assertHistory(history1 + history2 + history3 + history4,
+ ordered=False)
+ new = self.scheds.first.sched.tenant_layout_state.get('tenant-one')
+ # Verify we haven't performed a tenant reconfiguration
+ self.assertTrue(old == new)
+
+
+class TestIncludeBranchesProject(IncludeBranchesTestCase):
+ tenant_config_file = 'config/dynamic-only-project/include.yaml'
+
+ def test_include_branches(self):
+ history1 = [
+ dict(name='central-test', result='SUCCESS', changes='1,1'),
+ dict(name='project-test', result='SUCCESS', changes='1,1'),
+ ]
+ history2 = [
+ dict(name='central-test', result='SUCCESS', changes='2,1'),
+ ]
+ history3 = [
+ dict(name='central-test', result='SUCCESS', changes='3,1'),
+ ]
+ history4 = [
+ dict(name='central-test', result='SUCCESS', changes='2,1'),
+ ]
+ self._test_include_branches(history1, history2, history3, history4)
+
+
+class TestExcludeBranchesProject(IncludeBranchesTestCase):
+ tenant_config_file = 'config/dynamic-only-project/exclude.yaml'
+
+ def test_exclude_branches(self):
+ history1 = [
+ dict(name='central-test', result='SUCCESS', changes='1,1'),
+ dict(name='project-test', result='SUCCESS', changes='1,1'),
+ ]
+ history2 = [
+ dict(name='central-test', result='SUCCESS', changes='2,1'),
+ ]
+ history3 = [
+ dict(name='central-test', result='SUCCESS', changes='3,1'),
+ ]
+ history4 = [
+ dict(name='central-test', result='SUCCESS', changes='2,1'),
+ ]
+ self._test_include_branches(history1, history2, history3, history4)
+
+
+class TestDynamicBranchesProject(IncludeBranchesTestCase):
+ tenant_config_file = 'config/dynamic-only-project/dynamic.yaml'
+
+ def test_dynamic_branches(self):
+ history1 = [
+ dict(name='central-test', result='SUCCESS', changes='1,1'),
+ dict(name='project-test', result='SUCCESS', changes='1,1'),
+ ]
+ history2 = [
+ dict(name='central-test', result='SUCCESS', changes='2,1'),
+ dict(name='project-test', result='SUCCESS', changes='2,1'),
+ ]
+ history3 = [
+ dict(name='central-test', result='SUCCESS', changes='3,1'),
+ dict(name='project-dynamic', result='SUCCESS', changes='3,1'),
+ ]
+ history4 = [
+ dict(name='central-test', result='SUCCESS', changes='2,1'),
+ dict(name='project-test', result='SUCCESS', changes='2,1'),
+ ]
+ self._test_include_branches(history1, history2, history3, history4)