summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/base.py47
-rw-r--r--tests/fake_graphql.py31
-rw-r--r--tests/fakegithub.py51
-rw-r--r--tests/fixtures/config/ansible-versions/git/common-config/zuul.yaml12
-rw-r--r--tests/fixtures/config/intermediate/git/common-config/playbooks/base.yaml2
-rw-r--r--tests/fixtures/config/intermediate/git/common-config/zuul.yaml50
-rw-r--r--tests/fixtures/config/intermediate/git/org_project/README1
-rw-r--r--tests/fixtures/config/intermediate/main.yaml8
-rw-r--r--tests/fixtures/config/inventory/git/common-config/zuul.yaml9
-rw-r--r--tests/fixtures/config/inventory/git/org_project/.zuul.yaml1
-rw-r--r--tests/fixtures/config/inventory/git/org_project3/.zuul.yaml1
-rw-r--r--tests/fixtures/config/remote-action-modules/git/org_project/playbooks/uri-bad-dest.yaml6
-rw-r--r--tests/fixtures/config/remote-action-modules/git/org_project/playbooks/uri-bad-src.yaml7
-rw-r--r--tests/fixtures/config/remote-action-modules/git/org_project/playbooks/uri-bad-url.yaml14
-rw-r--r--tests/fixtures/config/remote-action-modules/git/org_project/playbooks/uri-good.yaml16
-rw-r--r--tests/fixtures/config/split-config/git/org_project1/.zuul.d/playbooks/.zuul.ignore0
-rw-r--r--tests/fixtures/config/split-config/git/org_project1/.zuul.d/playbooks/main.yaml8
-rw-r--r--tests/fixtures/zuul-default-ansible-version.conf2
-rw-r--r--tests/remote/test_remote_action_modules.py13
-rw-r--r--tests/remote/test_remote_zuul_json.py60
-rw-r--r--tests/remote/test_remote_zuul_stream.py100
-rw-r--r--tests/unit/test_configloader.py5
-rw-r--r--tests/unit/test_connection.py2
-rw-r--r--tests/unit/test_github_requirements.py5
-rw-r--r--tests/unit/test_gitlab_driver.py44
-rw-r--r--tests/unit/test_inventory.py24
-rw-r--r--tests/unit/test_merger_repo.py37
-rw-r--r--tests/unit/test_scheduler.py68
-rw-r--r--tests/unit/test_v3.py127
-rw-r--r--tests/unit/test_web.py8
30 files changed, 539 insertions, 220 deletions
diff --git a/tests/base.py b/tests/base.py
index 2811db7ce..94146ebff 100644
--- a/tests/base.py
+++ b/tests/base.py
@@ -1628,6 +1628,12 @@ class FakeGitlabConnection(gitlabconnection.GitlabConnection):
}
return (name, data)
+ @contextmanager
+ def enable_community_edition(self):
+ self.gl_client.community_edition = True
+ yield
+ self.gl_client.community_edition = False
+
class FakeGitlabAPIClient(gitlabconnection.GitlabAPIClient):
log = logging.getLogger("zuul.test.FakeGitlabAPIClient")
@@ -1635,6 +1641,7 @@ class FakeGitlabAPIClient(gitlabconnection.GitlabAPIClient):
def __init__(self, baseurl, api_token, merge_requests_db={}):
super(FakeGitlabAPIClient, self).__init__(baseurl, api_token)
self.merge_requests = merge_requests_db
+ self.community_edition = False
def gen_error(self, verb):
return {
@@ -1661,10 +1668,19 @@ class FakeGitlabAPIClient(gitlabconnection.GitlabAPIClient):
'title': mr.subject,
'state': mr.state,
'description': mr.description,
+ 'author': {
+ 'name': 'Administrator',
+ 'username': 'admin'
+ },
'updated_at': mr.updated_at.strftime('%Y-%m-%dT%H:%M:%S.%fZ'),
'sha': mr.sha,
'labels': mr.labels,
'merged_at': mr.merged_at,
+ 'diff_refs': {
+ 'base_sha': 'c380d3acebd181f13629a25d2e2acca46ffe1e00',
+ 'head_sha': '2be7ddb704c7b6b83732fdd5b9f09d5a397b5f8f',
+ 'start_sha': 'c380d3acebd181f13629a25d2e2acca46ffe1e00'
+ },
'merge_status': mr.merge_status,
}, 200, "", "GET"
@@ -1676,9 +1692,14 @@ class FakeGitlabAPIClient(gitlabconnection.GitlabAPIClient):
r'.+/projects/(.+)/merge_requests/(\d+)/approvals$', url)
if match:
mr = self._get_mr(match)
- return {
- 'approvals_left': 0 if mr.approved else 1,
- }, 200, "", "GET"
+ if not self.community_edition:
+ return {
+ 'approvals_left': 0 if mr.approved else 1,
+ }, 200, "", "GET"
+ else:
+ return {
+ 'approved': mr.approved,
+ }, 200, "", "GET"
def post(self, url, params=None, zuul_event_id=None):
@@ -1693,7 +1714,11 @@ class FakeGitlabAPIClient(gitlabconnection.GitlabAPIClient):
match = re.match(
r'.+/projects/(.+)/merge_requests/(\d+)/approve$', url)
if match:
+ assert 'sha' in params
mr = self._get_mr(match)
+ if params['sha'] != mr.sha:
+ return {'message': 'SHA does not match HEAD of source '
+ 'branch: <new_sha>'}, 409, "", "POST"
mr.approved = True
match = re.match(
@@ -1909,7 +1934,8 @@ class FakeGithubPullRequest(object):
def __init__(self, github, number, project, branch,
subject, upstream_root, files=[], number_of_commits=1,
- writers=[], body=None, body_text=None, draft=False):
+ writers=[], body=None, body_text=None, draft=False,
+ base_sha=None):
"""Creates a new PR with several commits.
Sends an event about opened PR."""
self.github = github
@@ -1936,7 +1962,7 @@ class FakeGithubPullRequest(object):
self.merge_message = None
self.state = 'open'
self.url = 'https://%s/%s/pull/%s' % (github.server, project, number)
- self._createPRRef()
+ self._createPRRef(base_sha=base_sha)
self._addCommitToRepo(files=files)
self._updateTimeStamp()
@@ -2103,10 +2129,11 @@ class FakeGithubPullRequest(object):
repo_path = os.path.join(self.upstream_root, self.project)
return git.Repo(repo_path)
- def _createPRRef(self):
+ def _createPRRef(self, base_sha=None):
+ base_sha = base_sha or 'refs/tags/init'
repo = self._getRepo()
GithubChangeReference.create(
- repo, self.getPRReference(), 'refs/tags/init')
+ repo, self.getPRReference(), base_sha)
def _addCommitToRepo(self, files=[], reset=False):
repo = self._getRepo()
@@ -2359,11 +2386,13 @@ class FakeGithubConnection(githubconnection.GithubConnection):
self.zuul_web_port = port
def openFakePullRequest(self, project, branch, subject, files=[],
- body=None, body_text=None, draft=False):
+ body=None, body_text=None, draft=False,
+ base_sha=None):
self.pr_number += 1
pull_request = FakeGithubPullRequest(
self, self.pr_number, project, branch, subject, self.upstream_root,
- files=files, body=body, body_text=body_text, draft=draft)
+ files=files, body=body, body_text=body_text, draft=draft,
+ base_sha=base_sha)
self.pull_requests[self.pr_number] = pull_request
return pull_request
diff --git a/tests/fake_graphql.py b/tests/fake_graphql.py
index 9e86f81ad..6c7567910 100644
--- a/tests/fake_graphql.py
+++ b/tests/fake_graphql.py
@@ -72,9 +72,14 @@ class FakeBranchProtectionRules(ObjectType):
return parent.values()
+class FakeActor(ObjectType):
+ login = String()
+
+
class FakeStatusContext(ObjectType):
state = String()
context = String()
+ creator = Field(FakeActor)
def resolve_state(parent, info):
state = parent.state.upper()
@@ -83,6 +88,9 @@ class FakeStatusContext(ObjectType):
def resolve_context(parent, info):
return parent.context
+ def resolve_creator(parent, info):
+ return parent.creator
+
class FakeStatus(ObjectType):
contexts = List(FakeStatusContext)
@@ -99,7 +107,9 @@ class FakeCheckRun(ObjectType):
return parent.name
def resolve_conclusion(parent, info):
- return parent.conclusion.upper()
+ if parent.conclusion:
+ return parent.conclusion.upper()
+ return None
class FakeCheckRuns(ObjectType):
@@ -109,11 +119,28 @@ class FakeCheckRuns(ObjectType):
return parent
+class FakeApp(ObjectType):
+ slug = String()
+ name = String()
+
+
class FakeCheckSuite(ObjectType):
+ app = Field(FakeApp)
checkRuns = Field(FakeCheckRuns, first=Int())
+ def resolve_app(parent, info):
+ if not parent:
+ return None
+ return parent[0].app
+
def resolve_checkRuns(parent, info, first=None):
- return parent
+ # We only want to return the latest result for a check run per app.
+ # Since the check runs are ordered from latest to oldest result we
+ # need to traverse the list in reverse order.
+ check_runs_by_name = {
+ "{}:{}".format(cr.app, cr.name): cr for cr in reversed(parent)
+ }
+ return check_runs_by_name.values()
class FakeCheckSuites(ObjectType):
diff --git a/tests/fakegithub.py b/tests/fakegithub.py
index 89b3ec73a..8e2f275eb 100644
--- a/tests/fakegithub.py
+++ b/tests/fakegithub.py
@@ -65,13 +65,18 @@ class FakeBranch(object):
}
+class FakeCreator:
+ def __init__(self, login):
+ self.login = login
+
+
class FakeStatus(object):
def __init__(self, state, url, description, context, user):
self.state = state
self.context = context
+ self.creator = FakeCreator(user)
self._url = url
self._description = description
- self._user = user
def as_dict(self):
return {
@@ -80,11 +85,17 @@ class FakeStatus(object):
'description': self._description,
'context': self.context,
'creator': {
- 'login': self._user
+ 'login': self.creator.login
}
}
+class FakeApp:
+ def __init__(self, name, slug):
+ self.name = name
+ self.slug = slug
+
+
class FakeCheckRun(object):
def __init__(self, name, details_url, output, status, conclusion,
completed_at, external_id, actions, app):
@@ -98,7 +109,7 @@ class FakeCheckRun(object):
self.completed_at = completed_at
self.external_id = external_id
self.actions = actions
- self.app = app
+ self.app = FakeApp(name=app, slug=app)
# Github automatically sets the status to "completed" if a conclusion
# is provided.
@@ -118,7 +129,8 @@ class FakeCheckRun(object):
"external_id": self.external_id,
"actions": self.actions,
"app": {
- "slug": self.app,
+ "slug": self.app.slug,
+ "name": self.app.name,
},
}
@@ -543,6 +555,9 @@ class FakePull(object):
},
'ref': pr.branch,
},
+ 'user': {
+ 'login': 'octocat'
+ },
'draft': pr.draft,
'mergeable': True,
'state': pr.state,
@@ -719,6 +734,13 @@ class FakeGithubClient(object):
def pull_request(self, owner, project, number):
fake_pr = self._data.pull_requests[int(number)]
+ repo = self.repository(owner, project)
+ # Ensure a commit for the head_sha exists so this can be resolved in
+ # graphql queries.
+ repo._commits.setdefault(
+ fake_pr.head_sha,
+ FakeCommit(fake_pr.head_sha)
+ )
return FakePull(fake_pr)
def search_issues(self, query):
@@ -735,9 +757,24 @@ class FakeGithubClient(object):
return re.match(r'[a-z0-9]{40}', s)
if query_is_sha(query):
- return (FakeIssueSearchResult(FakeIssue(pr))
- for pr in self._data.pull_requests.values()
- if pr.head_sha == query)
+ # Github returns all PR's that contain the sha in their history
+ result = []
+ for pr in self._data.pull_requests.values():
+ # Quick check if head sha matches
+ if pr.head_sha == query:
+ result.append(FakeIssueSearchResult(FakeIssue(pr)))
+ continue
+
+ # If head sha doesn't match it still could be in the pr history
+ repo = pr._getRepo()
+ commits = repo.iter_commits(
+ '%s...%s' % (pr.branch, pr.head_sha))
+ for commit in commits:
+ if commit.hexsha == query:
+ result.append(FakeIssueSearchResult(FakeIssue(pr)))
+ continue
+
+ return result
# Non-SHA queries are of the form:
#
diff --git a/tests/fixtures/config/ansible-versions/git/common-config/zuul.yaml b/tests/fixtures/config/ansible-versions/git/common-config/zuul.yaml
index 488e41a5c..8cef613a4 100644
--- a/tests/fixtures/config/ansible-versions/git/common-config/zuul.yaml
+++ b/tests/fixtures/config/ansible-versions/git/common-config/zuul.yaml
@@ -34,15 +34,7 @@
parent: ansible-version
vars:
test_ansible_version_major: 2
- test_ansible_version_minor: 7
-
-- job:
- name: ansible-27
- parent: ansible-version
- ansible-version: 2.7
- vars:
- test_ansible_version_major: 2
- test_ansible_version_minor: 7
+ test_ansible_version_minor: 8
- job:
name: ansible-28
@@ -66,7 +58,6 @@
check:
jobs:
- ansible-default
- - ansible-27
- ansible-28
- ansible-29
@@ -75,6 +66,5 @@
check:
jobs:
- ansible-default-zuul-conf
- - ansible-27
- ansible-28
- ansible-29
diff --git a/tests/fixtures/config/intermediate/git/common-config/playbooks/base.yaml b/tests/fixtures/config/intermediate/git/common-config/playbooks/base.yaml
new file mode 100644
index 000000000..f679dceae
--- /dev/null
+++ b/tests/fixtures/config/intermediate/git/common-config/playbooks/base.yaml
@@ -0,0 +1,2 @@
+- hosts: all
+ tasks: []
diff --git a/tests/fixtures/config/intermediate/git/common-config/zuul.yaml b/tests/fixtures/config/intermediate/git/common-config/zuul.yaml
new file mode 100644
index 000000000..6c787c91d
--- /dev/null
+++ b/tests/fixtures/config/intermediate/git/common-config/zuul.yaml
@@ -0,0 +1,50 @@
+- pipeline:
+ name: check
+ manager: independent
+ trigger:
+ gerrit:
+ - event: patchset-created
+ success:
+ gerrit:
+ Verified: 1
+ failure:
+ gerrit:
+ Verified: -1
+
+- job:
+ name: base
+ parent: null
+ run: playbooks/base.yaml
+
+- job:
+ name: job-abstract-intermediate
+ abstract: true
+ intermediate: true
+
+- job:
+ name: job-abstract
+ abstract: true
+ parent: job-abstract-intermediate
+
+# an intermediate, with an intermediate parent also
+- job:
+ name: job-another-intermediate
+ parent: job-abstract-intermediate
+ abstract: true
+ intermediate: true
+
+- job:
+ name: job-another-abstract
+ parent: job-another-intermediate
+ abstract: true
+
+- job:
+ name: job-actual
+ parent: job-another-abstract
+ run: playbooks/base.yaml
+
+- project:
+ name: org/project
+ check:
+ jobs: []
+
diff --git a/tests/fixtures/config/intermediate/git/org_project/README b/tests/fixtures/config/intermediate/git/org_project/README
new file mode 100644
index 000000000..9daeafb98
--- /dev/null
+++ b/tests/fixtures/config/intermediate/git/org_project/README
@@ -0,0 +1 @@
+test
diff --git a/tests/fixtures/config/intermediate/main.yaml b/tests/fixtures/config/intermediate/main.yaml
new file mode 100644
index 000000000..208e274b1
--- /dev/null
+++ b/tests/fixtures/config/intermediate/main.yaml
@@ -0,0 +1,8 @@
+- tenant:
+ name: tenant-one
+ source:
+ gerrit:
+ config-projects:
+ - common-config
+ untrusted-projects:
+ - org/project
diff --git a/tests/fixtures/config/inventory/git/common-config/zuul.yaml b/tests/fixtures/config/inventory/git/common-config/zuul.yaml
index 42c933201..32f64c592 100644
--- a/tests/fixtures/config/inventory/git/common-config/zuul.yaml
+++ b/tests/fixtures/config/inventory/git/common-config/zuul.yaml
@@ -100,15 +100,6 @@
run: playbooks/jinja2-message.yaml
- job:
- name: ansible-version27-inventory
- nodeset:
- nodes:
- - name: ubuntu-xenial
- label: ubuntu-xenial
- ansible-version: '2.7'
- run: playbooks/ansible-version.yaml
-
-- job:
name: ansible-version28-inventory
nodeset:
nodes:
diff --git a/tests/fixtures/config/inventory/git/org_project/.zuul.yaml b/tests/fixtures/config/inventory/git/org_project/.zuul.yaml
index 83961d75a..fd615518d 100644
--- a/tests/fixtures/config/inventory/git/org_project/.zuul.yaml
+++ b/tests/fixtures/config/inventory/git/org_project/.zuul.yaml
@@ -7,5 +7,4 @@
- executor-only-inventory
- group-inventory
- hostvars-inventory
- - ansible-version27-inventory
- ansible-version28-inventory
diff --git a/tests/fixtures/config/inventory/git/org_project3/.zuul.yaml b/tests/fixtures/config/inventory/git/org_project3/.zuul.yaml
index ac09fd329..6cf9faf88 100644
--- a/tests/fixtures/config/inventory/git/org_project3/.zuul.yaml
+++ b/tests/fixtures/config/inventory/git/org_project3/.zuul.yaml
@@ -6,5 +6,4 @@
- executor-only-inventory
- group-inventory
- hostvars-inventory
- - ansible-version27-inventory
- ansible-version28-inventory
diff --git a/tests/fixtures/config/remote-action-modules/git/org_project/playbooks/uri-bad-dest.yaml b/tests/fixtures/config/remote-action-modules/git/org_project/playbooks/uri-bad-dest.yaml
new file mode 100644
index 000000000..6c151842a
--- /dev/null
+++ b/tests/fixtures/config/remote-action-modules/git/org_project/playbooks/uri-bad-dest.yaml
@@ -0,0 +1,6 @@
+- hosts: localhost
+ tasks:
+ - name: Request with bad src
+ uri:
+ url: https://zuul.opendev.org
+ dest: /etc/zuul-uri-output-testing
diff --git a/tests/fixtures/config/remote-action-modules/git/org_project/playbooks/uri-bad-src.yaml b/tests/fixtures/config/remote-action-modules/git/org_project/playbooks/uri-bad-src.yaml
new file mode 100644
index 000000000..9a9460c9b
--- /dev/null
+++ b/tests/fixtures/config/remote-action-modules/git/org_project/playbooks/uri-bad-src.yaml
@@ -0,0 +1,7 @@
+- hosts: localhost
+ tasks:
+ - name: Request with bad src
+ uri:
+ url: https://zuul.opendev.org
+ method: POST
+ src: /etc/resolv.conf
diff --git a/tests/fixtures/config/remote-action-modules/git/org_project/playbooks/uri-bad-url.yaml b/tests/fixtures/config/remote-action-modules/git/org_project/playbooks/uri-bad-url.yaml
new file mode 100644
index 000000000..222f1925a
--- /dev/null
+++ b/tests/fixtures/config/remote-action-modules/git/org_project/playbooks/uri-bad-url.yaml
@@ -0,0 +1,14 @@
+- hosts: localhost
+ tasks:
+ - name: Request with bad url scheme
+ uri:
+ url: "file:///etc/resolv.conf"
+ dest: "{{ zuul.executor.log_root }}/resolv.conf"
+ - name: stat file that shouldnt exist
+ stat:
+ path: "{{ zuul.executor.log_root }}/resolv.conf"
+ register: test_stat
+ - name: Debug the stat
+ debug:
+ msg: "resolv.conf exists when it shouldn't"
+ when: test_stat.stat.exists
diff --git a/tests/fixtures/config/remote-action-modules/git/org_project/playbooks/uri-good.yaml b/tests/fixtures/config/remote-action-modules/git/org_project/playbooks/uri-good.yaml
new file mode 100644
index 000000000..0416cef4e
--- /dev/null
+++ b/tests/fixtures/config/remote-action-modules/git/org_project/playbooks/uri-good.yaml
@@ -0,0 +1,16 @@
+- hosts: localhost
+ tasks:
+ - name: Safe uri request from localhost
+ uri:
+ # We don't seem to have working ssl cert chains in
+ # the test bwrap context. Use http to workaround that
+ # and don't follow the redirect to https.
+ url: http://zuul.opendev.org
+ follow_redirects: none
+ return_content: yes
+ status_code:
+ - 301
+ - 302
+ - 303
+ - 307
+ - 308
diff --git a/tests/fixtures/config/split-config/git/org_project1/.zuul.d/playbooks/.zuul.ignore b/tests/fixtures/config/split-config/git/org_project1/.zuul.d/playbooks/.zuul.ignore
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/fixtures/config/split-config/git/org_project1/.zuul.d/playbooks/.zuul.ignore
diff --git a/tests/fixtures/config/split-config/git/org_project1/.zuul.d/playbooks/main.yaml b/tests/fixtures/config/split-config/git/org_project1/.zuul.d/playbooks/main.yaml
new file mode 100644
index 000000000..b136e8444
--- /dev/null
+++ b/tests/fixtures/config/split-config/git/org_project1/.zuul.d/playbooks/main.yaml
@@ -0,0 +1,8 @@
+# This is a playbook in the configuration directory which should be
+# ignored because the directory has a .zuul.ignore
+- hosts: all
+ tasks:
+
+ - name: foo
+ debug:
+ msg: blah
diff --git a/tests/fixtures/zuul-default-ansible-version.conf b/tests/fixtures/zuul-default-ansible-version.conf
index caecb38ef..ff15a0fed 100644
--- a/tests/fixtures/zuul-default-ansible-version.conf
+++ b/tests/fixtures/zuul-default-ansible-version.conf
@@ -9,7 +9,7 @@ server=127.0.0.1
[scheduler]
tenant_config=main.yaml
relative_priority=true
-default_ansible_version=2.7
+default_ansible_version=2.8
[merger]
git_dir=/tmp/zuul-test/merger-git
diff --git a/tests/remote/test_remote_action_modules.py b/tests/remote/test_remote_action_modules.py
index 23833f174..a147a9e5d 100644
--- a/tests/remote/test_remote_action_modules.py
+++ b/tests/remote/test_remote_action_modules.py
@@ -22,6 +22,7 @@ ERROR_LOCAL_CODE = "Executing local code is prohibited"
ERROR_SYNC_TO_OUTSIDE = "Syncing files to outside the working dir"
ERROR_SYNC_FROM_OUTSIDE = "Syncing files from outside the working dir"
ERROR_SYNC_RSH = "Using custom synchronize rsh is prohibited"
+ERROR_SCHEME_INVALID = "file urls are not allowed from localhost."
class FunctionalActionModulesMixIn:
@@ -221,13 +222,11 @@ class FunctionalActionModulesMixIn:
self._run_job('known-hosts-bad', 'FAILURE', ERROR_ACCESS_OUTSIDE)
-
-class TestActionModules27(AnsibleZuulTestCase, FunctionalActionModulesMixIn):
- ansible_version = '2.7'
-
- def setUp(self):
- super().setUp()
- self._setUp()
+ def test_uri_module(self):
+ self._run_job('uri-good', 'SUCCESS')
+ self._run_job('uri-bad-src', 'FAILURE', ERROR_ACCESS_OUTSIDE)
+ self._run_job('uri-bad-dest', 'FAILURE', ERROR_ACCESS_OUTSIDE)
+ self._run_job('uri-bad-url', 'FAILURE', ERROR_SCHEME_INVALID)
class TestActionModules28(AnsibleZuulTestCase, FunctionalActionModulesMixIn):
diff --git a/tests/remote/test_remote_zuul_json.py b/tests/remote/test_remote_zuul_json.py
index e93f3f119..688894190 100644
--- a/tests/remote/test_remote_zuul_json.py
+++ b/tests/remote/test_remote_zuul_json.py
@@ -91,8 +91,11 @@ class FunctionalZuulJSONMixIn:
text = self._get_json_as_text(build)
json_result = json.loads(text)
tasks = json_result[0]['plays'][0]['tasks']
+ # NOTE(pabelanger): In 2.8 gather_facts are now logged as an
+ # expected action.
expected_actions = [
- 'debug', 'debug', 'debug', 'copy', 'find', 'stat', 'debug'
+ 'gather_facts', 'debug', 'debug', 'debug', 'copy', 'find',
+ 'stat', 'debug'
]
for i, expected in enumerate(expected_actions):
host_result = tasks[i]['hosts']['controller']
@@ -108,10 +111,12 @@ class FunctionalZuulJSONMixIn:
self.assertIn('json-role', text)
json_result = json.loads(text)
- role_name = json_result[0]['plays'][0]['tasks'][0]['role']['name']
+ # NOTE(pabelanger): In 2.8 gather_facts are now logged as the
+ # first task.
+ role_name = json_result[0]['plays'][0]['tasks'][1]['role']['name']
self.assertEqual('json-role', role_name)
- role_path = json_result[0]['plays'][0]['tasks'][0]['role']['path']
+ role_path = json_result[0]['plays'][0]['tasks'][1]['role']['path']
self.assertEqual('json-role', os.path.basename(role_path))
def test_json_time_log(self):
@@ -143,58 +148,17 @@ class FunctionalZuulJSONMixIn:
dateutil.parser.parse(play_end_time)
-class TestZuulJSON27(AnsibleZuulTestCase, FunctionalZuulJSONMixIn):
- ansible_version = '2.7'
+class TestZuulJSON28(AnsibleZuulTestCase, FunctionalZuulJSONMixIn):
+ ansible_version = '2.8'
def setUp(self):
super().setUp()
self._setUp()
-class TestZuulJSON28(AnsibleZuulTestCase, FunctionalZuulJSONMixIn):
- ansible_version = '2.8'
+class TestZuulJSON29(AnsibleZuulTestCase, FunctionalZuulJSONMixIn):
+ ansible_version = '2.9'
def setUp(self):
super().setUp()
self._setUp()
-
- def test_json_task_action(self):
- job = self._run_job('no-log')
- with self.jobLog(job):
- build = self.history[-1]
- self.assertEqual(build.result, 'SUCCESS')
-
- text = self._get_json_as_text(build)
- json_result = json.loads(text)
- tasks = json_result[0]['plays'][0]['tasks']
- # NOTE(pabelanger): In 2.8 gather_facts are now logged as an
- # expected action.
- expected_actions = [
- 'gather_facts', 'debug', 'debug', 'debug', 'copy', 'find',
- 'stat', 'debug'
- ]
- for i, expected in enumerate(expected_actions):
- host_result = tasks[i]['hosts']['controller']
- self.assertEquals(expected, host_result['action'])
-
- def test_json_role_log(self):
- job = self._run_job('json-role')
- with self.jobLog(job):
- build = self.history[-1]
- self.assertEqual(build.result, 'SUCCESS')
-
- text = self._get_json_as_text(build)
- self.assertIn('json-role', text)
-
- json_result = json.loads(text)
- # NOTE(pabelanger): In 2.8 gather_facts are now logged as the
- # first task.
- role_name = json_result[0]['plays'][0]['tasks'][1]['role']['name']
- self.assertEqual('json-role', role_name)
-
- role_path = json_result[0]['plays'][0]['tasks'][1]['role']['path']
- self.assertEqual('json-role', os.path.basename(role_path))
-
-
-class TestZuulJSON29(TestZuulJSON28):
- ansible_version = '2.9'
diff --git a/tests/remote/test_remote_zuul_stream.py b/tests/remote/test_remote_zuul_stream.py
index 9fef472b5..aed500769 100644
--- a/tests/remote/test_remote_zuul_stream.py
+++ b/tests/remote/test_remote_zuul_stream.py
@@ -158,9 +158,11 @@ class FunctionalZuulStreamMixIn:
self.assertLogLine(
r'controller \| ok: Runtime: \d:\d\d:\d\d\.\d\d\d\d\d\d', text)
self.assertLogLine('PLAY RECAP', text)
+ # NOTE(pabelanger): Ansible 2.8 added new stats
+ # skipped, rescued, ignored.
self.assertLogLine(
- r'controller \| ok: \d+ changed: \d+ unreachable: 0 failed: 1',
- text)
+ r'controller \| ok: \d+ changed: \d+ unreachable: 0 failed: 0 '
+ 'skipped: 0 rescued: 1 ignored: 0', text)
self.assertLogLine(
r'RUN END RESULT_NORMAL: \[untrusted : review.example.com/'
r'org/project/playbooks/command.yaml@master]', text)
@@ -210,103 +212,17 @@ class FunctionalZuulStreamMixIn:
self.assertLogLine(regex, text)
-class TestZuulStream27(AnsibleZuulTestCase, FunctionalZuulStreamMixIn):
- ansible_version = '2.7'
+class TestZuulStream28(AnsibleZuulTestCase, FunctionalZuulStreamMixIn):
+ ansible_version = '2.8'
def setUp(self):
super().setUp()
self._setUp()
-class TestZuulStream28(AnsibleZuulTestCase, FunctionalZuulStreamMixIn):
- ansible_version = '2.8'
+class TestZuulStream29(AnsibleZuulTestCase, FunctionalZuulStreamMixIn):
+ ansible_version = '2.9'
def setUp(self):
super().setUp()
self._setUp()
-
- def test_command(self):
- job = self._run_job('command')
- with self.jobLog(job):
- build = self.history[-1]
- self.assertEqual(build.result, 'SUCCESS')
-
- text = self._get_job_output(build)
- self.assertLogLine(
- r'RUN START: \[untrusted : review.example.com/org/project/'
- r'playbooks/command.yaml@master\]', text)
- self.assertLogLine(r'PLAY \[all\]', text)
- self.assertLogLine(
- r'Ansible version={}'.format(self.ansible_version), text)
- self.assertLogLine(r'TASK \[Show contents of first file\]', text)
- self.assertLogLine(r'controller \| command test one', text)
- self.assertLogLine(
- r'controller \| ok: Runtime: \d:\d\d:\d\d\.\d\d\d\d\d\d', text)
- self.assertLogLine(r'TASK \[Show contents of second file\]', text)
- self.assertLogLine(r'compute1 \| command test two', text)
- self.assertLogLine(r'controller \| command test two', text)
- self.assertLogLine(r'compute1 \| This is a rescue task', text)
- self.assertLogLine(r'controller \| This is a rescue task', text)
- self.assertLogLine(r'compute1 \| This is an always task', text)
- self.assertLogLine(r'controller \| This is an always task', text)
- self.assertLogLine(r'compute1 \| This is a handler', text)
- self.assertLogLine(r'controller \| This is a handler', text)
- self.assertLogLine(r'controller \| First free task', text)
- self.assertLogLine(r'controller \| Second free task', text)
- self.assertLogLine(r'controller \| This is a shell task after an '
- 'included role', text)
- self.assertLogLine(r'compute1 \| This is a shell task after an '
- 'included role', text)
- self.assertLogLine(r'controller \| This is a command task after '
- 'an included role', text)
- self.assertLogLine(r'compute1 \| This is a command task after an '
- 'included role', text)
- self.assertLogLine(r'controller \| This is a shell task with '
- 'delegate compute1', text)
- self.assertLogLine(r'controller \| This is a shell task with '
- 'delegate controller', text)
- self.assertLogLine(r'compute1 \| item_in_loop1', text)
- self.assertLogLine(r'compute1 \| ok: Item: item_in_loop1 '
- r'Runtime: \d:\d\d:\d\d\.\d\d\d\d\d\d', text)
- self.assertLogLine(r'compute1 \| item_in_loop2', text)
- self.assertLogLine(r'compute1 \| ok: Item: item_in_loop2 '
- r'Runtime: \d:\d\d:\d\d\.\d\d\d\d\d\d', text)
- self.assertLogLine(r'compute1 \| failed_in_loop1', text)
- self.assertLogLine(r'compute1 \| ok: Item: failed_in_loop1 '
- r'Result: 1', text)
- self.assertLogLine(r'compute1 \| failed_in_loop2', text)
- self.assertLogLine(r'compute1 \| ok: Item: failed_in_loop2 '
- r'Result: 1', text)
- self.assertLogLine(r'compute1 \| .*No such file or directory: .*'
- r'\'/remote-shelltask/somewhere/'
- r'that/does/not/exist\'', text)
- self.assertLogLine(r'controller \| .*No such file or directory: .*'
- r'\'/remote-shelltask/somewhere/'
- r'that/does/not/exist\'', text)
- self.assertLogLine(
- r'controller \| ok: Runtime: \d:\d\d:\d\d\.\d\d\d\d\d\d', text)
- self.assertLogLine('PLAY RECAP', text)
- # NOTE(pabelanger): Ansible 2.8 added new stats
- # skipped, rescued, ignored.
- self.assertLogLine(
- r'controller \| ok: \d+ changed: \d+ unreachable: 0 failed: 0 '
- 'skipped: 0 rescued: 1 ignored: 0', text)
- self.assertLogLine(
- r'RUN END RESULT_NORMAL: \[untrusted : review.example.com/'
- r'org/project/playbooks/command.yaml@master]', text)
-
- # Run a pre-defined job that is defined in a trusted repo to test
- # localhost tasks.
- job = self._run_job('command-localhost', create=False)
- with self.jobLog(job):
- build = self.history[-1]
- self.assertEqual(build.result, 'SUCCESS')
-
- text = self._get_job_output(build)
- self.assertLogLine(r'localhost \| .*No such file or directory: .*'
- r'\'/local-shelltask/somewhere/'
- r'that/does/not/exist\'', text)
-
-
-class TestZuulStream29(TestZuulStream28):
- ansible_version = '2.9'
diff --git a/tests/unit/test_configloader.py b/tests/unit/test_configloader.py
index cf156e156..9dbba9e60 100644
--- a/tests/unit/test_configloader.py
+++ b/tests/unit/test_configloader.py
@@ -397,6 +397,11 @@ class TestSplitConfig(ZuulTestCase):
self.assertIn('project1-project2-integration',
project1_config[0].pipelines['check'].job_list.jobs)
+ # This check ensures the .zuul.ignore flag file is working in
+ # the config directory.
+ self.assertEquals(
+ len(tenant.layout.loading_errors), 0)
+
def test_dynamic_split_config(self):
in_repo_conf = textwrap.dedent(
"""
diff --git a/tests/unit/test_connection.py b/tests/unit/test_connection.py
index f64de8c7c..ebabb6a0b 100644
--- a/tests/unit/test_connection.py
+++ b/tests/unit/test_connection.py
@@ -555,6 +555,8 @@ class TestMQTTConnection(ZuulTestCase):
'tenant-one/zuul_start/check/org/project/master')
mqtt_payload = start_event['msg']
self.assertEquals(mqtt_payload['project'], 'org/project')
+ self.assertEqual(len(mqtt_payload['commit_id']), 40)
+ self.assertEquals(mqtt_payload['owner'], 'username')
self.assertEquals(mqtt_payload['branch'], 'master')
self.assertEquals(mqtt_payload['buildset']['result'], None)
self.assertEquals(mqtt_payload['buildset']['builds'][0]['job_name'],
diff --git a/tests/unit/test_github_requirements.py b/tests/unit/test_github_requirements.py
index e542f80f9..bde2c5ca8 100644
--- a/tests/unit/test_github_requirements.py
+++ b/tests/unit/test_github_requirements.py
@@ -92,6 +92,11 @@ class TestGithubRequirements(ZuulTestCase):
project = 'org/project2'
A = self.fake_github.openFakePullRequest(project, 'master', 'A')
+ # Create second PR which contains the head of A in its history. Zuul
+ # should not get disturbed by the existence of this one.
+ self.fake_github.openFakePullRequest(
+ project, 'master', 'A', base_sha=A.head_sha)
+
# An error status should not cause it to be enqueued
self.fake_github.setCommitStatus(project, A.head_sha, 'error',
context='tenant-one/check')
diff --git a/tests/unit/test_gitlab_driver.py b/tests/unit/test_gitlab_driver.py
index 11edaf0c4..c9a08c56b 100644
--- a/tests/unit/test_gitlab_driver.py
+++ b/tests/unit/test_gitlab_driver.py
@@ -162,6 +162,27 @@ class TestGitlabDriver(ZuulTestCase):
self.assertEqual('check-approval', zuulvars['pipeline'])
@simple_layout('layouts/basic-gitlab.yaml', driver='gitlab')
+ def test_merge_request_updated_during_build(self):
+
+ A = self.fake_gitlab.openFakeMergeRequest('org/project', 'master', 'A')
+ self.fake_gitlab.emitEvent(A.getMergeRequestOpenedEvent())
+ old = A.sha
+ A.addCommit()
+ new = A.sha
+ self.assertNotEqual(old, new)
+ self.waitUntilSettled()
+
+ self.assertEqual(2, len(self.history))
+ # MR must not be approved: tested commit isn't current commit
+ self.assertFalse(A.approved)
+
+ self.fake_gitlab.emitEvent(A.getMergeRequestUpdatedEvent())
+ self.waitUntilSettled()
+
+ self.assertEqual(4, len(self.history))
+ self.assertTrue(A.approved)
+
+ @simple_layout('layouts/basic-gitlab.yaml', driver='gitlab')
def test_merge_request_labeled(self):
A = self.fake_gitlab.openFakeMergeRequest('org/project', 'master', 'A')
@@ -560,6 +581,29 @@ class TestGitlabDriver(ZuulTestCase):
self.assertEqual(1, len(self.history))
@simple_layout('layouts/requirements-gitlab.yaml', driver='gitlab')
+ def test_approval_require_community_edition(self):
+
+ with self.fake_gitlab.enable_community_edition():
+ A = self.fake_gitlab.openFakeMergeRequest(
+ 'org/project2', 'master', 'A')
+
+ self.fake_gitlab.emitEvent(A.getMergeRequestOpenedEvent())
+ self.waitUntilSettled()
+ self.assertEqual(0, len(self.history))
+
+ A.approved = True
+
+ self.fake_gitlab.emitEvent(A.getMergeRequestUpdatedEvent())
+ self.waitUntilSettled()
+ self.assertEqual(1, len(self.history))
+
+ A.approved = False
+
+ self.fake_gitlab.emitEvent(A.getMergeRequestUpdatedEvent())
+ self.waitUntilSettled()
+ self.assertEqual(1, len(self.history))
+
+ @simple_layout('layouts/requirements-gitlab.yaml', driver='gitlab')
def test_label_require(self):
A = self.fake_gitlab.openFakeMergeRequest(
diff --git a/tests/unit/test_inventory.py b/tests/unit/test_inventory.py
index af45aebb7..024e438a4 100644
--- a/tests/unit/test_inventory.py
+++ b/tests/unit/test_inventory.py
@@ -167,30 +167,6 @@ class TestInventoryAutoPython(TestInventoryBase):
self.executor_server.release()
self.waitUntilSettled()
- def test_auto_python_ansible27_inventory(self):
- inventory = self._get_build_inventory('ansible-version27-inventory')
-
- all_nodes = ('ubuntu-xenial',)
- self.assertIn('all', inventory)
- self.assertIn('hosts', inventory['all'])
- self.assertIn('vars', inventory['all'])
- for node_name in all_nodes:
- self.assertIn(node_name, inventory['all']['hosts'])
- node_vars = inventory['all']['hosts'][node_name]
- self.assertEqual(
- '/usr/bin/python2', node_vars['ansible_python_interpreter'])
-
- self.assertIn('zuul', inventory['all']['vars'])
- z_vars = inventory['all']['vars']['zuul']
- self.assertIn('executor', z_vars)
- self.assertIn('src_root', z_vars['executor'])
- self.assertIn('job', z_vars)
- self.assertEqual(z_vars['job'], 'ansible-version27-inventory')
- self.assertEqual(z_vars['message'], 'QQ==')
-
- self.executor_server.release()
- self.waitUntilSettled()
-
class TestInventory(TestInventoryBase):
diff --git a/tests/unit/test_merger_repo.py b/tests/unit/test_merger_repo.py
index 28e4b4456..9a626ea56 100644
--- a/tests/unit/test_merger_repo.py
+++ b/tests/unit/test_merger_repo.py
@@ -731,3 +731,40 @@ class TestMerger(ZuulTestCase):
ref_map[foo_zuul_ref].commit.hexsha,
merge_state[("gerrit", "org/project", "foo")]
)
+
+ def test_stale_index_lock_cleanup(self):
+ # Stop the running executor's merger. We needed it running to merge
+ # things during test boostrapping but now it is just in the way.
+ self.executor_server.merger_gearworker.stop()
+ self.executor_server.merger_gearworker.join()
+ # Start the merger and do a merge to populate the repo on disk
+ self._startMerger()
+
+ 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(A.data['status'], 'MERGED')
+
+ # Stop the merger so we can modify the git repo
+ self.merge_server.stop()
+ self.merge_server.join()
+
+ # Add an index.lock file
+ fpath = os.path.join(self.merger_src_root, 'review.example.com',
+ 'org', 'project1', '.git', 'index.lock')
+ with open(fpath, 'w'):
+ pass
+ self.assertTrue(os.path.exists(fpath))
+
+ # Start a new merger and check that we can still merge things
+ self._startMerger()
+
+ # This will fail if git can't modify the repo due to a stale lock file.
+ B = self.fake_gerrit.addFakeChange('org/project1', 'master', 'B')
+ B.addApproval('Code-Review', 2)
+ self.fake_gerrit.addEvent(B.addApproval('Approved', 1))
+ self.waitUntilSettled()
+ self.assertEqual(B.data['status'], 'MERGED')
+
+ self.assertFalse(os.path.exists(fpath))
diff --git a/tests/unit/test_scheduler.py b/tests/unit/test_scheduler.py
index f92206d55..3c9abbe56 100644
--- a/tests/unit/test_scheduler.py
+++ b/tests/unit/test_scheduler.py
@@ -8365,3 +8365,71 @@ class TestSchedulerSmartReconfiguration(ZuulTestCase):
def test_smart_reconfiguration_command_socket(self):
"Test that live reconfiguration works using command socket"
self._test_smart_reconfiguration(command_socket=True)
+
+
+class TestReconfigureBranch(ZuulTestCase):
+
+ def _setupTenantReconfigureTime(self):
+ self.old = self.scheds.first.sched.tenant_last_reconfigured\
+ .get('tenant-one', 0)
+
+ def _createBranch(self):
+ self.create_branch('org/project1', 'stable')
+ self.fake_gerrit.addEvent(
+ self.fake_gerrit.getFakeBranchCreatedEvent(
+ 'org/project1', 'stable'))
+ self.waitUntilSettled()
+
+ def _deleteBranch(self):
+ self.delete_branch('org/project1', 'stable')
+ self.fake_gerrit.addEvent(
+ self.fake_gerrit.getFakeBranchDeletedEvent(
+ 'org/project1', 'stable'))
+ self.waitUntilSettled()
+
+ def _expectReconfigure(self, doReconfigure):
+ new = self.scheds.first.sched.tenant_last_reconfigured\
+ .get('tenant-one', 0)
+ if doReconfigure:
+ self.assertLess(self.old, new)
+ else:
+ self.assertEqual(self.old, new)
+ self.old = new
+
+
+class TestReconfigureBranchCreateDeleteSshHttp(TestReconfigureBranch):
+ tenant_config_file = 'config/single-tenant/main.yaml'
+ config_file = 'zuul-gerrit-web.conf'
+
+ def test_reconfigure_cache_branch_create_delete(self):
+ "Test that cache is updated clear on branch creation/deletion"
+ self._setupTenantReconfigureTime()
+ self._createBranch()
+ self._expectReconfigure(True)
+ self._deleteBranch()
+ self._expectReconfigure(True)
+
+
+class TestReconfigureBranchCreateDeleteSsh(TestReconfigureBranch):
+ tenant_config_file = 'config/single-tenant/main.yaml'
+
+ def test_reconfigure_cache_branch_create_delete(self):
+ "Test that cache is updated clear on branch creation/deletion"
+ self._setupTenantReconfigureTime()
+ self._createBranch()
+ self._expectReconfigure(True)
+ self._deleteBranch()
+ self._expectReconfigure(True)
+
+
+class TestReconfigureBranchCreateDeleteHttp(TestReconfigureBranch):
+ tenant_config_file = 'config/single-tenant/main.yaml'
+ config_file = 'zuul-gerrit-no-stream.conf'
+
+ def test_reconfigure_cache_branch_create_delete(self):
+ "Test that cache is updated clear on branch creation/deletion"
+ self._setupTenantReconfigureTime()
+ self._createBranch()
+ self._expectReconfigure(True)
+ self._deleteBranch()
+ self._expectReconfigure(True)
diff --git a/tests/unit/test_v3.py b/tests/unit/test_v3.py
index dc8e8f6a1..3f8315e40 100644
--- a/tests/unit/test_v3.py
+++ b/tests/unit/test_v3.py
@@ -16,9 +16,10 @@ import io
import json
import logging
import os
+import sys
import textwrap
import gc
-from unittest import skip
+from unittest import skip, skipIf
import paramiko
@@ -221,6 +222,81 @@ class TestAbstract(ZuulTestCase):
self.assertEqual(A.patchsets[-1]['approvals'][0]['value'], '1')
+class TestIntermediate(ZuulTestCase):
+ tenant_config_file = 'config/intermediate/main.yaml'
+
+ def test_intermediate_fail(self):
+ # you can not instantiate from an intermediate job
+ in_repo_conf = textwrap.dedent(
+ """
+ - job:
+ name: job-instantiate-intermediate
+ parent: job-abstract-intermediate
+
+ - project:
+ check:
+ jobs:
+ - job-instantiate-intermediate
+ """)
+
+ 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 only inherit to another abstract job',
+ A.messages[0])
+
+ def test_intermediate_config_fail(self):
+ # an intermediate job must also be abstract
+ in_repo_conf = textwrap.dedent(
+ """
+ - job:
+ name: job-intermediate-but-not-abstract
+ intermediate: true
+ abstract: false
+
+ - project:
+ check:
+ jobs:
+ - job-intermediate-but-not-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('An intermediate job must also be abstract',
+ A.messages[0])
+
+ def test_intermediate_several(self):
+ # test passing through several intermediate jobs
+ in_repo_conf = textwrap.dedent(
+ """
+ - project:
+ name: org/project
+ check:
+ jobs:
+ - job-actual
+ """)
+
+ 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'
@@ -1457,11 +1533,13 @@ class TestInRepoConfig(ZuulTestCase):
"A should report failure")
self.assertIn('not a list', A.messages[0],
"A should have a syntax error reported")
+ self.assertIn('job: foo', A.messages[0],
+ "A should display the failing list")
def test_yaml_dict_error(self):
in_repo_conf = textwrap.dedent(
"""
- - job
+ - job_not_a_dict
""")
file_dict = {'.zuul.yaml': in_repo_conf}
@@ -1476,6 +1554,8 @@ class TestInRepoConfig(ZuulTestCase):
"A should report failure")
self.assertIn('not a dictionary', A.messages[0],
"A should have a syntax error reported")
+ self.assertIn('job_not_a_dict', A.messages[0],
+ "A should list the bad key")
def test_yaml_duplicate_key_error(self):
in_repo_conf = textwrap.dedent(
@@ -1517,6 +1597,41 @@ class TestInRepoConfig(ZuulTestCase):
"A should report failure")
self.assertIn('has more than one key', A.messages[0],
"A should have a syntax error reported")
+ self.assertIn("job: null\n name: project-test2", A.messages[0],
+ "A should have the failing section displayed")
+
+ # This is non-deterministic without default dict ordering, which
+ # happended with python 3.7.
+ @skipIf(sys.version_info < (3, 7), "non-deterministic on < 3.7")
+ def test_yaml_error_truncation_message(self):
+ in_repo_conf = textwrap.dedent(
+ """
+ - job:
+ name: project-test2
+ this: is
+ a: long
+ set: of
+ keys: that
+ should: be
+ truncated: ok
+ """)
+
+ 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")
+ self.assertIn("job: null\n name: project-test2", A.messages[0],
+ "A should have the failing section displayed")
+ self.assertIn("...", A.messages[0],
+ "A should have the failing section truncated")
def test_yaml_unknown_error(self):
in_repo_conf = textwrap.dedent(
@@ -1537,6 +1652,8 @@ class TestInRepoConfig(ZuulTestCase):
"A should report failure")
self.assertIn('not recognized', A.messages[0],
"A should have a syntax error reported")
+ self.assertIn('foobar:\n foo: bar', A.messages[0],
+ "A should report the bad keys")
def test_invalid_job_secret_var_name(self):
in_repo_conf = textwrap.dedent(
@@ -2849,10 +2966,6 @@ class FunctionalAnsibleMixIn(object):
self._test_plugins(plugin_tests)
-class TestAnsible27(AnsibleZuulTestCase, FunctionalAnsibleMixIn):
- ansible_version = '2.7'
-
-
class TestAnsible28(AnsibleZuulTestCase, FunctionalAnsibleMixIn):
ansible_version = '2.8'
@@ -6597,7 +6710,6 @@ class TestAnsibleVersion(AnsibleZuulTestCase):
self.assertHistory([
dict(name='ansible-default', result='SUCCESS', changes='1,1'),
- dict(name='ansible-27', result='SUCCESS', changes='1,1'),
dict(name='ansible-28', result='SUCCESS', changes='1,1'),
dict(name='ansible-29', result='SUCCESS', changes='1,1'),
], ordered=False)
@@ -6618,7 +6730,6 @@ class TestDefaultAnsibleVersion(AnsibleZuulTestCase):
self.assertHistory([
dict(name='ansible-default-zuul-conf', result='SUCCESS',
changes='1,1'),
- dict(name='ansible-27', result='SUCCESS', changes='1,1'),
dict(name='ansible-28', result='SUCCESS', changes='1,1'),
dict(name='ansible-29', result='SUCCESS', changes='1,1'),
], ordered=False)
diff --git a/tests/unit/test_web.py b/tests/unit/test_web.py
index 6a74a8a96..784d4ba3a 100644
--- a/tests/unit/test_web.py
+++ b/tests/unit/test_web.py
@@ -341,6 +341,7 @@ class TestWeb(BaseTestWeb):
'dependencies': [],
'description': None,
'files': [],
+ 'intermediate': False,
'irrelevant_files': [],
'match_on_config_updates': True,
'final': False,
@@ -385,6 +386,7 @@ class TestWeb(BaseTestWeb):
'dependencies': [],
'description': None,
'files': [],
+ 'intermediate': False,
'irrelevant_files': [],
'match_on_config_updates': True,
'final': False,
@@ -434,6 +436,7 @@ class TestWeb(BaseTestWeb):
'description': None,
'files': [],
'final': False,
+ 'intermediate': False,
'irrelevant_files': [],
'match_on_config_updates': True,
'name': 'test-job',
@@ -555,6 +558,7 @@ class TestWeb(BaseTestWeb):
'description': None,
'files': [],
'final': False,
+ 'intermediate': False,
'irrelevant_files': [],
'match_on_config_updates': True,
'name': 'project-merge',
@@ -592,6 +596,7 @@ class TestWeb(BaseTestWeb):
'description': None,
'files': [],
'final': False,
+ 'intermediate': False,
'irrelevant_files': [],
'match_on_config_updates': True,
'name': 'project-test1',
@@ -629,6 +634,7 @@ class TestWeb(BaseTestWeb):
'description': None,
'files': [],
'final': False,
+ 'intermediate': False,
'irrelevant_files': [],
'match_on_config_updates': True,
'name': 'project-test2',
@@ -666,6 +672,7 @@ class TestWeb(BaseTestWeb):
'description': None,
'files': [],
'final': False,
+ 'intermediate': False,
'irrelevant_files': [],
'match_on_config_updates': True,
'name': 'project1-project2-integration',
@@ -723,6 +730,7 @@ class TestWeb(BaseTestWeb):
'description': None,
'files': [],
'final': False,
+ 'intermediate': False,
'irrelevant_files': [],
'match_on_config_updates': True,
'name': 'project-post',