Files
zuul/tests/unit/test_pagure_driver.py
James E. Blair 8c804042fb Add "debug" flag to triggers
This allows users to create pipeline triggers that provide expanded
debug information in reports.  This includes not only the debug
info currently available with the project-pipeline-config "debug" flag
(which includes decisions about running jobs), but additionally includes
information about why the change may not have been enqueued (and in
these cases, we will exceptionally report a non-enqueued item in order
to get this information to the user).

The intended workflow is:

1) User approves change
2) User is baffled by why change does not appear in pipeline
3) User leaves a comment with "gate debug" or a similar label/tag/etc
4) Zuul reports with a comment indicating why it was not enqueued
   (depends on abandoned change, etc).

To make this more useful, the pipeline manager will now add several more
bits of information to the "warnings" list for non-enqueue conditions.
Also, the canMerge methods of the connections may now return a
FalseWithReason so their reasoning may end up in these messages.

Tests of this are added to each of the 4 code-review systems since the
attribute is set on the trigger itself, which is driver-specific.
These tests add coverage of the parsing and also exercise the canMerge
method.  The Gerrit driver test includes several more variations to
exercise each of the new points in the pipeline manager that can
report a non-enqueued item.

While the git, timer, and zuul drivers also support this for completeness,
testing is not added to them since it is unlikely to be used.

Change-Id: Ifa59406bda40c2ede98ba275894b4bd05663cd6c
2025-06-12 14:15:43 -07:00

1125 lines
42 KiB
Python

# Copyright 2019 Red Hat
#
# 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 os
import re
import git
import yaml
import socket
from testtools.matchers import MatchesRegex
from zuul.lib import strings
from zuul.zk.layout import LayoutState
from tests.base import ZuulTestCase, simple_layout
from tests.base import ZuulWebFixture
EMPTY_LAYOUT_STATE = LayoutState("", "", 0, None, {}, -1)
class TestPagureDriver(ZuulTestCase):
config_file = 'zuul-pagure-driver.conf'
@simple_layout('layouts/basic-pagure.yaml', driver='pagure')
def test_pull_request_opened(self):
initial_comment = "This is the\nPR initial_comment."
A = self.fake_pagure.openFakePullRequest(
'org/project', 'master', 'A', initial_comment=initial_comment)
self.fake_pagure.emitEvent(A.getPullRequestOpenedEvent())
self.waitUntilSettled()
self.assertEqual('SUCCESS',
self.getJobFromHistory('project-test1').result)
self.assertEqual('SUCCESS',
self.getJobFromHistory('project-test2').result)
job = self.getJobFromHistory('project-test2')
zuulvars = job.parameters['zuul']
self.assertEqual(str(A.number), zuulvars['change'])
self.assertEqual(str(A.commit_stop), zuulvars['patchset'])
self.assertEqual(str(A.commit_stop), zuulvars['commit_id'])
self.assertEqual('master', zuulvars['branch'])
self.assertEquals('https://pagure/org/project/pull-request/1',
zuulvars['items'][0]['change_url'])
self.assertEqual(zuulvars["message"],
strings.b64encode(initial_comment))
self.assertEqual(2, len(self.history))
self.assertEqual(2, len(A.comments))
self.assertEqual(
A.comments[0]['comment'], "Starting check jobs.")
self.assertThat(
A.comments[1]['comment'],
MatchesRegex(r'.*\[project-test1 \]\(.*\).*', re.DOTALL))
self.assertThat(
A.comments[1]['comment'],
MatchesRegex(r'.*\[project-test2 \]\(.*\).*', re.DOTALL))
self.assertEqual(1, len(A.flags))
self.assertEqual('success', A.flags[0]['status'])
@simple_layout('layouts/basic-pagure.yaml', driver='pagure')
def test_pull_request_updated(self):
A = self.fake_pagure.openFakePullRequest('org/project', 'master', 'A')
pr_tip1 = A.commit_stop
self.fake_pagure.emitEvent(A.getPullRequestOpenedEvent())
self.waitUntilSettled()
self.assertEqual(2, len(self.history))
self.assertHistory(
[
{'name': 'project-test1', 'changes': '1,%s' % pr_tip1},
{'name': 'project-test2', 'changes': '1,%s' % pr_tip1},
], ordered=False
)
self.fake_pagure.emitEvent(A.getPullRequestUpdatedEvent())
pr_tip2 = A.commit_stop
self.waitUntilSettled()
self.assertEqual(4, len(self.history))
self.assertHistory(
[
{'name': 'project-test1', 'changes': '1,%s' % pr_tip1},
{'name': 'project-test2', 'changes': '1,%s' % pr_tip1},
{'name': 'project-test1', 'changes': '1,%s' % pr_tip2},
{'name': 'project-test2', 'changes': '1,%s' % pr_tip2}
], ordered=False
)
@simple_layout('layouts/basic-pagure.yaml', driver='pagure')
def test_pull_request_updated_builds_aborted(self):
A = self.fake_pagure.openFakePullRequest('org/project', 'master', 'A')
pr_tip1 = A.commit_stop
self.executor_server.hold_jobs_in_build = True
self.fake_pagure.emitEvent(A.getPullRequestOpenedEvent())
self.waitUntilSettled()
self.fake_pagure.emitEvent(A.getPullRequestUpdatedEvent())
pr_tip2 = A.commit_stop
self.waitUntilSettled()
self.executor_server.hold_jobs_in_build = False
self.executor_server.release()
self.waitUntilSettled()
self.assertHistory(
[
{'name': 'project-test1', 'result': 'ABORTED',
'changes': '1,%s' % pr_tip1},
{'name': 'project-test2', 'result': 'ABORTED',
'changes': '1,%s' % pr_tip1},
{'name': 'project-test1', 'changes': '1,%s' % pr_tip2},
{'name': 'project-test2', 'changes': '1,%s' % pr_tip2}
], ordered=False
)
@simple_layout('layouts/basic-pagure.yaml', driver='pagure')
def test_pull_request_commented(self):
A = self.fake_pagure.openFakePullRequest('org/project', 'master', 'A')
self.fake_pagure.emitEvent(A.getPullRequestOpenedEvent())
self.waitUntilSettled()
self.assertEqual(2, len(self.history))
self.fake_pagure.emitEvent(
A.getPullRequestCommentedEvent('I like that change'))
self.waitUntilSettled()
self.assertEqual(2, len(self.history))
self.fake_pagure.emitEvent(
A.getPullRequestCommentedEvent('recheck'))
self.waitUntilSettled()
self.assertEqual(4, len(self.history))
self.fake_pagure.emitEvent(
A.getPullRequestInitialCommentEvent('Initial comment edited'))
self.waitUntilSettled()
self.assertEqual(6, len(self.history))
@simple_layout('layouts/basic-pagure.yaml', driver='pagure')
def test_pull_request_with_dyn_reconf(self):
zuul_yaml = [
{'job': {
'name': 'project-test3',
'run': 'job.yaml'
}},
{'project': {
'check': {
'jobs': [
'project-test3'
]
}
}}
]
playbook = "- hosts: all\n tasks: []"
A = self.fake_pagure.openFakePullRequest(
'org/project', 'master', 'A')
A.addCommit(
{'.zuul.yaml': yaml.dump(zuul_yaml),
'job.yaml': playbook}
)
self.fake_pagure.emitEvent(A.getPullRequestOpenedEvent())
self.waitUntilSettled()
self.assertEqual('SUCCESS',
self.getJobFromHistory('project-test1').result)
self.assertEqual('SUCCESS',
self.getJobFromHistory('project-test2').result)
self.assertEqual('SUCCESS',
self.getJobFromHistory('project-test3').result)
@simple_layout('layouts/basic-pagure.yaml', driver='pagure')
def test_ref_updated(self):
event = self.fake_pagure.getGitReceiveEvent('org/project')
expected_newrev = event[1]['msg']['end_commit']
expected_oldrev = event[1]['msg']['old_commit']
self.fake_pagure.emitEvent(event)
self.waitUntilSettled()
self.assertEqual(1, len(self.history))
self.assertEqual(
'SUCCESS',
self.getJobFromHistory('project-post-job').result)
job = self.getJobFromHistory('project-post-job')
zuulvars = job.parameters['zuul']
self.assertEqual('refs/heads/master', zuulvars['ref'])
self.assertEqual('post', zuulvars['pipeline'])
self.assertEqual('project-post-job', zuulvars['job'])
self.assertEqual('master', zuulvars['branch'])
self.assertEqual(
'https://pagure/org/project/c/%s' % zuulvars['newrev'],
zuulvars['change_url'])
self.assertEqual(expected_newrev, zuulvars['newrev'])
self.assertEqual(expected_oldrev, zuulvars['oldrev'])
self.assertEqual(expected_newrev, zuulvars['commit_id'])
@simple_layout('layouts/basic-pagure.yaml', driver='pagure')
def test_ref_created(self):
self.create_branch('org/project', 'stable-1.0')
path = os.path.join(self.upstream_root, 'org/project')
repo = git.Repo(path)
newrev = repo.commit('refs/heads/stable-1.0').hexsha
event = self.fake_pagure.getGitBranchEvent(
'org/project', 'stable-1.0', 'creation', newrev)
old = self.scheds.first.sched.tenant_layout_state.get(
'tenant-one', EMPTY_LAYOUT_STATE)
self.fake_pagure.emitEvent(event)
self.waitUntilSettled()
new = self.scheds.first.sched.tenant_layout_state.get(
'tenant-one', EMPTY_LAYOUT_STATE)
# New timestamp should be greater than the old timestamp
self.assertLess(old, new)
self.assertEqual(1, len(self.history))
self.assertEqual(
'SUCCESS',
self.getJobFromHistory('project-post-job').result)
job = self.getJobFromHistory('project-post-job')
zuulvars = job.parameters['zuul']
self.assertEqual('refs/heads/stable-1.0', zuulvars['ref'])
self.assertEqual('post', zuulvars['pipeline'])
self.assertEqual('project-post-job', zuulvars['job'])
self.assertEqual('stable-1.0', zuulvars['branch'])
self.assertEqual(newrev, zuulvars['newrev'])
@simple_layout('layouts/basic-pagure.yaml', driver='pagure')
def test_ref_deleted(self):
event = self.fake_pagure.getGitBranchEvent(
'org/project', 'stable-1.0', 'deletion', '0' * 40)
self.fake_pagure.emitEvent(event)
self.waitUntilSettled()
self.assertEqual(0, len(self.history))
@simple_layout('layouts/basic-pagure.yaml', driver='pagure')
def test_ref_updated_and_tenant_reconfigure(self):
self.waitUntilSettled()
old = self.scheds.first.sched.tenant_layout_state.get(
'tenant-one', EMPTY_LAYOUT_STATE)
zuul_yaml = [
{'job': {
'name': 'project-post-job2',
'run': 'job.yaml'
}},
{'project': {
'post': {
'jobs': [
'project-post-job2'
]
}
}}
]
playbook = "- hosts: all\n tasks: []"
self.create_commit(
'org/project',
{'.zuul.yaml': yaml.dump(zuul_yaml),
'job.yaml': playbook},
message='Add InRepo configuration'
)
event = self.fake_pagure.getGitReceiveEvent('org/project')
self.fake_pagure.emitEvent(event)
self.waitUntilSettled()
new = self.scheds.first.sched.tenant_layout_state.get(
'tenant-one', EMPTY_LAYOUT_STATE)
# New timestamp should be greater than the old timestamp
self.assertLess(old, new)
self.assertHistory(
[{'name': 'project-post-job'},
{'name': 'project-post-job2'},
], ordered=False
)
@simple_layout('layouts/files-pagure.yaml', driver='pagure')
def test_pull_matched_file_event(self):
A = self.fake_pagure.openFakePullRequest(
'org/project', 'master', 'A',
files={'random.txt': 'test', 'build-requires': 'test'})
self.fake_pagure.emitEvent(A.getPullRequestOpenedEvent())
self.waitUntilSettled()
self.assertEqual(1, len(self.history))
B = self.fake_pagure.openFakePullRequest('org/project', 'master', 'B',
files={'random.txt': 'test2'})
self.fake_pagure.emitEvent(B.getPullRequestOpenedEvent())
self.waitUntilSettled()
self.assertEqual(1, len(self.history))
C = self.fake_pagure.openFakePullRequest(
'org/project', 'master', 'C',
files={'build-requires': 'test'})
self.fake_pagure.emitEvent(C.getPullRequestOpenedEvent())
self.waitUntilSettled()
self.assertEqual(2, len(self.history))
@simple_layout('layouts/basic-pagure.yaml', driver='pagure')
def test_tag_created(self):
path = os.path.join(self.upstream_root, 'org/project')
repo = git.Repo(path)
repo.create_tag('1.0')
tagsha = repo.tags['1.0'].commit.hexsha
event = self.fake_pagure.getGitTagCreatedEvent(
'org/project', '1.0', tagsha)
self.fake_pagure.emitEvent(event)
self.waitUntilSettled()
self.assertEqual(1, len(self.history))
self.assertEqual(
'SUCCESS',
self.getJobFromHistory('project-tag-job').result)
job = self.getJobFromHistory('project-tag-job')
zuulvars = job.parameters['zuul']
self.assertEqual('refs/tags/1.0', zuulvars['ref'])
self.assertEqual('tag', zuulvars['pipeline'])
self.assertEqual('project-tag-job', zuulvars['job'])
self.assertEqual(tagsha, zuulvars['newrev'])
@simple_layout('layouts/requirements-pagure.yaml', driver='pagure')
def test_pr_score_require_1_vote(self):
A = self.fake_pagure.openFakePullRequest(
'org/project1', 'master', 'A')
self.fake_pagure.emitEvent(
A.getPullRequestCommentedEvent("I like that change"))
self.waitUntilSettled()
self.assertEqual(0, len(self.history))
self.fake_pagure.emitEvent(
A.getPullRequestCommentedEvent(":thumbsup:"))
self.waitUntilSettled()
self.assertEqual(1, len(self.history))
self.assertEqual(
'SUCCESS',
self.getJobFromHistory('project-test').result)
@simple_layout('layouts/requirements-pagure.yaml', driver='pagure')
def test_pr_score_require_2_votes(self):
A = self.fake_pagure.openFakePullRequest(
'org/project2', 'master', 'A')
self.fake_pagure.emitEvent(
A.getPullRequestCommentedEvent("I like that change"))
self.waitUntilSettled()
self.assertEqual(0, len(self.history))
self.fake_pagure.emitEvent(
A.getPullRequestCommentedEvent(":thumbsup:"))
self.waitUntilSettled()
self.assertEqual(0, len(self.history))
self.fake_pagure.emitEvent(
A.getPullRequestCommentedEvent(":thumbsdown:"))
self.waitUntilSettled()
self.assertEqual(0, len(self.history))
self.fake_pagure.emitEvent(
A.getPullRequestCommentedEvent(":thumbsup:"))
self.waitUntilSettled()
self.assertEqual(0, len(self.history))
self.fake_pagure.emitEvent(
A.getPullRequestCommentedEvent(":thumbsup:"))
self.waitUntilSettled()
self.assertEqual(1, len(self.history))
@simple_layout('layouts/requirements-pagure.yaml', driver='pagure')
def test_status_trigger(self):
A = self.fake_pagure.openFakePullRequest(
'org/project3', 'master', 'A')
self.fake_pagure.emitEvent(
A.getPullRequestStatusSetEvent("failure"))
self.waitUntilSettled()
self.assertEqual(0, len(self.history))
self.fake_pagure.emitEvent(
A.getPullRequestStatusSetEvent("success"))
self.waitUntilSettled()
self.assertEqual(1, len(self.history))
@simple_layout('layouts/requirements-pagure.yaml', driver='pagure')
def test_tag_trigger(self):
A = self.fake_pagure.openFakePullRequest(
'org/project4', 'master', 'A')
self.fake_pagure.emitEvent(
A.getPullRequestTagAddedEvent(["lambda"]))
self.waitUntilSettled()
self.assertEqual(0, len(self.history))
self.fake_pagure.emitEvent(
A.getPullRequestTagAddedEvent(["gateit", "lambda"]))
self.waitUntilSettled()
self.assertEqual(1, len(self.history))
self.fake_pagure.emitEvent(
A.getPullRequestTagAddedEvent(["mergeit"]))
self.waitUntilSettled()
self.assertEqual(2, len(self.history))
@simple_layout('layouts/requirements-pagure.yaml', driver='pagure')
def test_tag_require(self):
A = self.fake_pagure.openFakePullRequest(
'org/project5', 'master', 'A')
self.fake_pagure.emitEvent(A.getPullRequestUpdatedEvent())
self.waitUntilSettled()
self.assertEqual(0, len(self.history))
A.tags = ["lambda"]
self.fake_pagure.emitEvent(A.getPullRequestUpdatedEvent())
self.waitUntilSettled()
self.assertEqual(0, len(self.history))
A.tags = ["lambda", "gateit"]
self.fake_pagure.emitEvent(A.getPullRequestUpdatedEvent())
self.waitUntilSettled()
self.assertEqual(1, len(self.history))
A.tags = []
self.fake_pagure.emitEvent(A.getPullRequestUpdatedEvent())
self.waitUntilSettled()
self.assertEqual(1, len(self.history))
@simple_layout('layouts/requirements-pagure.yaml', driver='pagure')
def test_flag_require(self):
A = self.fake_pagure.openFakePullRequest(
'org/project7', 'master', 'A')
# CI status from other CIs must not be handled
self.fake_pagure.emitEvent(
A.getPullRequestStatusSetEvent("success", username="notzuul"))
self.waitUntilSettled()
self.assertEqual(0, len(self.history))
self.assertEqual(1, len(A.flags))
self.fake_pagure.emitEvent(
A.getPullRequestStatusSetEvent("failure"))
self.waitUntilSettled()
self.assertEqual(0, len(self.history))
self.assertEqual(2, len(A.flags))
self.fake_pagure.emitEvent(
A.getPullRequestStatusSetEvent("success"))
self.waitUntilSettled()
self.assertEqual(1, len(self.history))
self.assertEqual(2, len(A.flags))
@simple_layout('layouts/requirements-pagure.yaml', driver='pagure')
def test_pull_request_closed(self):
A = self.fake_pagure.openFakePullRequest(
'org/project6', 'master', 'A')
self.fake_pagure.emitEvent(A.getPullRequestOpenedEvent())
self.waitUntilSettled()
self.assertEqual(0, len(self.history))
# Validate a closed but not merged PR does not trigger the pipeline
self.fake_pagure.emitEvent(A.getPullRequestClosedEvent(merged=False))
self.waitUntilSettled()
self.assertEqual(0, len(self.history))
# Reset the status to Open
# Validate a closed and merged PR triggers the pipeline
A.status = 'Open'
A.is_merged = False
self.fake_pagure.emitEvent(A.getPullRequestClosedEvent())
self.waitUntilSettled()
self.assertEqual(1, len(self.history))
@simple_layout('layouts/merging-pagure.yaml', driver='pagure')
def test_merge_action_in_independent(self):
A = self.fake_pagure.openFakePullRequest(
'org/project1', 'master', 'A')
self.fake_pagure.emitEvent(A.getPullRequestOpenedEvent())
self.waitUntilSettled()
self.assertEqual(1, len(self.history))
self.assertEqual('SUCCESS',
self.getJobFromHistory('project-test').result)
self.assertEqual('Merged', A.status)
@simple_layout('layouts/merging-pagure.yaml', driver='pagure')
def test_merge_action_in_dependent(self):
A = self.fake_pagure.openFakePullRequest(
'org/project2', 'master', 'A')
self.fake_pagure.emitEvent(A.getPullRequestOpenedEvent())
self.waitUntilSettled()
# connection.canMerge is not validated
self.assertEqual(0, len(self.history))
# Set the mergeable PR flag to a expected value
A.cached_merge_status = 'MERGE'
self.fake_pagure.emitEvent(A.getPullRequestOpenedEvent())
self.waitUntilSettled()
# connection.canMerge is not validated
self.assertEqual(0, len(self.history))
# Set the score threshold as reached
# Here we use None that means no specific score is required
A.threshold_reached = None
self.fake_pagure.emitEvent(A.getPullRequestOpenedEvent())
self.waitUntilSettled()
# connection.canMerge is not validated
self.assertEqual(0, len(self.history))
# Set CI flag as passed CI
A.addFlag('success', 'https://url', 'Build passed')
self.fake_pagure.emitEvent(A.getPullRequestOpenedEvent())
self.waitUntilSettled()
# connection.canMerge is validated
self.assertEqual(1, len(self.history))
self.assertEqual('SUCCESS',
self.getJobFromHistory('project-test').result)
self.assertEqual('Merged', A.status)
@simple_layout('layouts/crd-pagure.yaml', driver='pagure')
def test_crd_independent(self):
# Create a change in project1 that a project2 change will depend on
A = self.fake_pagure.openFakePullRequest('org/project1', 'master', 'A')
# Create a commit in B that sets the dependency on A
msg = "Depends-On: %s" % A.url
B = self.fake_pagure.openFakePullRequest(
'org/project2', 'master', 'B', initial_comment=msg)
# Make an event to re-use
event = B.getPullRequestCommentedEvent('A comment')
self.fake_pagure.emitEvent(event)
self.waitUntilSettled()
# The changes for the job from project2 should include the project1
# PR content
changes = self.getJobFromHistory(
'project2-test', 'org/project2').changes
self.assertEqual(changes, "%s,%s %s,%s" % (A.number,
A.commit_stop,
B.number,
B.commit_stop))
# There should be no more changes in the queue
tenant = self.scheds.first.sched.abide.tenants.get('tenant-one')
self.assertEqual(len(
tenant.layout.pipeline_managers['check'].state.queues), 0)
@simple_layout('layouts/crd-pagure.yaml', driver='pagure')
def test_crd_dependent(self):
# Create a change in project3 that a project4 change will depend on
A = self.fake_pagure.openFakePullRequest('org/project3', 'master', 'A')
# Create a commit in B that sets the dependency on A
msg = "Depends-On: %s" % A.url
B = self.fake_pagure.openFakePullRequest(
'org/project4', 'master', 'B', initial_comment=msg)
# Make an event to re-use
event = B.getPullRequestCommentedEvent('A comment')
self.fake_pagure.emitEvent(event)
self.waitUntilSettled()
# Neither A and B can't merge (no flag, no score threshold)
self.assertEqual(0, len(self.history))
B.threshold_reached = True
B.addFlag('success', 'https://url', 'Build passed')
self.fake_pagure.emitEvent(event)
self.waitUntilSettled()
# B can't merge as A got no flag, no score threshold
self.assertEqual(0, len(self.history))
A.threshold_reached = True
A.addFlag('success', 'https://url', 'Build passed')
self.fake_pagure.emitEvent(event)
self.waitUntilSettled()
# The changes for the job from project4 should include the project3
# PR content
changes = self.getJobFromHistory(
'project4-test', 'org/project4').changes
self.assertEqual(changes, "%s,%s %s,%s" % (A.number,
A.commit_stop,
B.number,
B.commit_stop))
self.assertTrue(A.is_merged)
self.assertTrue(B.is_merged)
@simple_layout('layouts/crd-pagure.yaml', driver='pagure')
def test_crd_needed_changes(self):
# Given change A and B, where B depends on A, when A
# completes B should be enqueued (using a shared queue)
# Create a change in project3 that a project4 change will depend on
A = self.fake_pagure.openFakePullRequest('org/project3', 'master', 'A')
A.threshold_reached = True
A.addFlag('success', 'https://url', 'Build passed')
# Set B to depend on A
msg = "Depends-On: %s" % A.url
B = self.fake_pagure.openFakePullRequest(
'org/project4', 'master', 'B', initial_comment=msg)
# Make the driver aware of change B by sending an event
# At that moment B can't merge
self.fake_pagure.emitEvent(B.getPullRequestCommentedEvent('A comment'))
# Now set B mergeable
B.threshold_reached = True
B.addFlag('success', 'https://url', 'Build passed')
# Enqueue A, which will make the scheduler detect that B is
# depending on so B will be enqueue as well.
self.fake_pagure.emitEvent(A.getPullRequestCommentedEvent('A comment'))
self.waitUntilSettled()
# The changes for the job from project4 should include the project3
# PR content
changes = self.getJobFromHistory(
'project4-test', 'org/project4').changes
self.assertEqual(changes, "%s,%s %s,%s" % (A.number,
A.commit_stop,
B.number,
B.commit_stop))
self.assertTrue(A.is_merged)
self.assertTrue(B.is_merged)
@simple_layout('layouts/files-pagure.yaml', driver='pagure')
def test_changed_file_match_filter(self):
files = {'{:03d}.txt'.format(n): 'test' for n in range(300)}
files["foobar-requires"] = "test"
files["to-be-removed"] = "test"
A = self.fake_pagure.openFakePullRequest(
'org/project', 'master', 'A', files=files)
self.fake_pagure.emitEvent(A.getPullRequestOpenedEvent())
self.waitUntilSettled()
# project-test1 and project-test2 should be run
self.assertEqual(2, len(self.history))
@simple_layout('layouts/files-pagure.yaml', driver='pagure')
def test_changed_and_reverted_file_not_match_filter(self):
files = {'{:03d}.txt'.format(n): 'test' for n in range(3)}
files["foobar-requires"] = "test"
files["to-be-removed"] = "test"
A = self.fake_pagure.openFakePullRequest(
'org/project', 'master', 'A', files=files)
A.addCommit(delete_files=['to-be-removed'])
self.fake_pagure.emitEvent(A.getPullRequestOpenedEvent())
self.waitUntilSettled()
# Only project-test1 should be run, because the file to-be-removed
# is reverted and not in changed files to trigger project-test2
self.assertEqual(1, len(self.history))
@simple_layout("layouts/basic-pagure.yaml", driver="pagure")
def test_get_project_branch_sha(self):
# Exercise this method since it's only called from timer
# triggers
source = self.fake_pagure.source
project = source.getProject('org/project')
self.assertIsNotNone(source.getProjectBranchSha(project, 'master'))
@simple_layout('layouts/pagure-pipeline-trigger-debug.yaml',
driver='pagure')
def test_pagure_pipeline_trigger_debug(self):
# Test that we get debug info for a pipeline debug trigger
A = self.fake_pagure.openFakePullRequest("org/project", "master", "A")
self.fake_pagure.emitEvent(A.getPullRequestOpenedEvent())
self.waitUntilSettled()
self.assertFalse(A.is_merged)
self.assertEqual(1, len(A.comments))
self.assertIn('Debug information:',
A.comments[0]['comment'])
# Test the canMerge code path
B = self.fake_pagure.openFakePullRequest("org/project", "master", "B")
B.draft = True
self.fake_pagure.emitEvent(
B.getPullRequestTagAddedEvent(["gateit"]))
self.waitUntilSettled()
self.assertFalse(B.is_merged)
self.assertEqual(2, len(B.comments))
self.assertIn("can not be merged",
B.comments[1]['comment'])
class TestPagureToGerritCRD(ZuulTestCase):
config_file = 'zuul-crd-pagure.conf'
tenant_config_file = 'config/cross-source-pagure/gerrit.yaml'
def test_crd_gate(self):
"Test cross-repo dependencies"
A = self.fake_pagure.openFakePullRequest('pagure/project2', 'master',
'A')
B = self.fake_gerrit.addFakeChange('gerrit/project1', 'master', 'B')
# A Depends-On: B
A.editInitialComment('Depends-On: %s\n' % (B.data['url']))
A.addFlag('success', 'https://url', 'Build passed')
A.threshold_reached = True
B.addApproval('Code-Review', 2)
# Make A enter the pipeline
self.fake_pagure.emitEvent(
A.getPullRequestCommentedEvent(":thumbsup:"))
self.waitUntilSettled()
# Expect not merged as B not approved yet
self.assertFalse(A.is_merged)
self.assertEqual(B.data['status'], 'NEW')
for connection in self.scheds.first.connections.connections.values():
connection.maintainCache([], max_age=0)
B.addApproval('Approved', 1)
self.fake_pagure.emitEvent(
A.getPullRequestCommentedEvent(":thumbsup:"))
self.waitUntilSettled()
self.assertTrue(A.is_merged)
self.assertEqual(B.data['status'], 'MERGED')
self.assertEqual(len(A.comments), 4)
self.assertEqual(B.reported, 2)
changes = self.getJobFromHistory(
'project-merge', 'pagure/project2').changes
self.assertEqual(changes, '1,1 1,%s' % A.commit_stop)
def test_crd_check(self):
"Test cross-repo dependencies in independent pipelines"
A = self.fake_pagure.openFakePullRequest('pagure/project2', 'master',
'A')
B = self.fake_gerrit.addFakeChange(
'gerrit/project1', 'master', 'B')
# A Depends-On: B
A.editInitialComment('Depends-On: %s\n' % (B.data['url'],))
self.executor_server.hold_jobs_in_build = True
self.fake_pagure.emitEvent(A.getPullRequestUpdatedEvent())
self.waitUntilSettled()
self.assertTrue(self.builds[0].hasChanges(A, B))
self.executor_server.hold_jobs_in_build = False
self.executor_server.release()
self.waitUntilSettled()
self.assertFalse(A.is_merged)
self.assertEqual(B.data['status'], 'NEW')
self.assertEqual(len(A.comments), 2)
self.assertEqual(B.reported, 0)
changes = self.getJobFromHistory(
'project-merge', 'pagure/project2').changes
self.assertEqual(changes, '1,1 1,%s' % A.commit_stop)
class TestGerritToPagureCRD(ZuulTestCase):
config_file = 'zuul-crd-pagure.conf'
tenant_config_file = 'config/cross-source-pagure/gerrit.yaml'
def test_crd_gate(self):
"Test cross-repo dependencies"
A = self.fake_gerrit.addFakeChange('gerrit/project1', 'master', 'A')
B = self.fake_pagure.openFakePullRequest('pagure/project2', 'master',
'B')
A.addApproval('Code-Review', 2)
AM2 = self.fake_gerrit.addFakeChange('gerrit/project1', 'master',
'AM2')
AM1 = self.fake_gerrit.addFakeChange('gerrit/project1', 'master',
'AM1')
AM2.setMerged()
AM1.setMerged()
# A -> AM1 -> AM2
# A Depends-On: B
# M2 is here to make sure it is never queried. If it is, it
# means zuul is walking down the entire history of merged
# changes.
A.setDependsOn(AM1, 1)
AM1.setDependsOn(AM2, 1)
A.data['commitMessage'] = '%s\n\nDepends-On: %s\n' % (
A.subject, B.url)
self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
self.waitUntilSettled()
self.assertEqual(A.data['status'], 'NEW')
self.assertFalse(B.is_merged)
for connection in self.scheds.first.connections.connections.values():
connection.maintainCache([], max_age=0)
B.addFlag('success', 'https://url', 'Build passed')
B.threshold_reached = True
self.fake_pagure.emitEvent(
B.getPullRequestCommentedEvent(":thumbsup:"))
self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
self.waitUntilSettled()
self.assertEqual(AM2.queried, 0)
self.assertEqual(A.data['status'], 'MERGED')
self.assertTrue(B.is_merged)
self.assertEqual(A.reported, 2)
self.assertEqual(len(B.comments), 3)
changes = self.getJobFromHistory(
'project-merge', 'gerrit/project1').changes
self.assertEqual(changes, '1,%s 1,1' % B.commit_stop)
def test_crd_check(self):
"Test cross-repo dependencies in independent pipelines"
A = self.fake_gerrit.addFakeChange('gerrit/project1', 'master', 'A')
B = self.fake_pagure.openFakePullRequest(
'pagure/project2', 'master', 'B')
# A Depends-On: B
A.data['commitMessage'] = '%s\n\nDepends-On: %s\n' % (
A.subject, B.url)
self.executor_server.hold_jobs_in_build = True
self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
self.waitUntilSettled()
self.assertTrue(self.builds[0].hasChanges(A, B))
self.executor_server.hold_jobs_in_build = False
self.executor_server.release()
self.waitUntilSettled()
self.assertEqual(A.data['status'], 'NEW')
self.assertFalse(B.is_merged)
self.assertEqual(A.reported, 1)
self.assertEqual(len(B.comments), 0)
changes = self.getJobFromHistory(
'project-merge', 'gerrit/project1').changes
self.assertEqual(changes, '1,%s 1,1' % B.commit_stop)
class TestPagureToGithubCRD(ZuulTestCase):
config_file = 'zuul-crd-pagure.conf'
tenant_config_file = 'config/cross-source-pagure/github.yaml'
def test_crd_gate(self):
"Test cross-repo dependencies"
A = self.fake_pagure.openFakePullRequest('pagure/project2', 'master',
'A')
B = self.fake_github.openFakePullRequest('github/project1', 'master',
'B')
# A Depends-On: B
A.editInitialComment('Depends-On: %s\n' % (B.url))
A.addFlag('success', 'https://url', 'Build passed')
A.threshold_reached = True
# Make A enter the pipeline
self.fake_pagure.emitEvent(
A.getPullRequestCommentedEvent(":thumbsup:"))
self.waitUntilSettled()
# Expect not merged as B not approved yet
self.assertFalse(A.is_merged)
self.assertFalse(B.is_merged)
for connection in self.scheds.first.connections.connections.values():
connection.maintainCache([], max_age=0)
B.addLabel('approved')
self.fake_pagure.emitEvent(
A.getPullRequestCommentedEvent(":thumbsup:"))
self.waitUntilSettled()
self.assertTrue(A.is_merged)
self.assertTrue(B.is_merged)
self.assertEqual(len(A.comments), 4)
self.assertEqual(len(B.comments), 2)
changes = self.getJobFromHistory(
'project-merge', 'pagure/project2').changes
self.assertEqual(changes, '1,%s 1,%s' % (B.head_sha, A.commit_stop))
def test_crd_check(self):
"Test cross-repo dependencies in independent pipelines"
A = self.fake_pagure.openFakePullRequest('pagure/project2', 'master',
'A')
B = self.fake_github.openFakePullRequest('github/project1', 'master',
'A')
# A Depends-On: B
A.editInitialComment('Depends-On: %s\n' % B.url)
self.executor_server.hold_jobs_in_build = True
self.fake_pagure.emitEvent(A.getPullRequestUpdatedEvent())
self.waitUntilSettled()
self.assertTrue(self.builds[0].hasChanges(A, B))
self.executor_server.hold_jobs_in_build = False
self.executor_server.release()
self.waitUntilSettled()
self.assertFalse(A.is_merged)
self.assertFalse(B.is_merged)
self.assertEqual(len(A.comments), 2)
self.assertEqual(len(A.comments), 2)
changes = self.getJobFromHistory(
'project-merge', 'pagure/project2').changes
self.assertEqual(changes, '1,%s 1,%s' % (B.head_sha, A.commit_stop))
class TestGithubToPagureCRD(ZuulTestCase):
config_file = 'zuul-crd-pagure.conf'
tenant_config_file = 'config/cross-source-pagure/github.yaml'
# Those tests are also using the fake github implementation which
# means that every scheduler gets a different fake github instance.
# Thus, assertions might fail depending on which scheduler did the
# interaction with Github.
scheduler_count = 1
def test_crd_gate(self):
"Test cross-repo dependencies"
A = self.fake_github.openFakePullRequest('github/project1', 'master',
'A')
B = self.fake_pagure.openFakePullRequest('pagure/project2', 'master',
'B')
# A Depends-On: B
A.editBody('Depends-On: %s\n' % B.url)
event = A.addLabel('approved')
self.fake_github.emitEvent(event)
self.waitUntilSettled()
self.assertFalse(A.is_merged)
self.assertFalse(B.is_merged)
for connection in self.scheds.first.connections.connections.values():
connection.maintainCache([], max_age=0)
B.addFlag('success', 'https://url', 'Build passed')
B.threshold_reached = True
self.fake_pagure.emitEvent(
B.getPullRequestCommentedEvent(":thumbsup:"))
self.fake_github.emitEvent(event)
self.waitUntilSettled()
self.assertTrue(A.is_merged)
self.assertTrue(B.is_merged)
self.assertEqual(len(A.comments), 2)
self.assertEqual(len(B.comments), 3)
changes = self.getJobFromHistory(
'project-merge', 'github/project1').changes
self.assertEqual(changes, '1,%s 1,%s' % (B.commit_stop, A.head_sha))
def test_crd_check(self):
"Test cross-repo dependencies in independent pipelines"
A = self.fake_github.openFakePullRequest(
'github/project1', 'master', 'A')
B = self.fake_pagure.openFakePullRequest(
'pagure/project2', 'master', 'B')
# A Depends-On: B
self.executor_server.hold_jobs_in_build = True
self.fake_github.emitEvent(A.editBody('Depends-On: %s\n' % B.url))
self.waitUntilSettled()
self.assertTrue(self.builds[0].hasChanges(A, B))
self.executor_server.hold_jobs_in_build = False
self.executor_server.release()
self.waitUntilSettled()
self.assertFalse(A.is_merged)
self.assertFalse(B.is_merged)
self.assertEqual(len(A.comments), 1)
self.assertEqual(len(B.comments), 0)
changes = self.getJobFromHistory(
'project-merge', 'github/project1').changes
self.assertEqual(changes, '1,%s 1,%s' % (B.commit_stop, A.head_sha))
class TestPagureWebhook(ZuulTestCase):
config_file = 'zuul-pagure-driver.conf'
def setUp(self):
super(TestPagureWebhook, self).setUp()
# Start the web server
self.web = self.useFixture(
ZuulWebFixture(self.config, self.test_config,
self.additional_event_queues, self.upstream_root,
self.poller_events,
self.git_url_with_auth, self.addCleanup,
self.test_root))
host = '127.0.0.1'
# Wait until web server is started
while True:
port = self.web.port
try:
with socket.create_connection((host, port)):
break
except ConnectionRefusedError:
pass
self.fake_pagure.setZuulWebPort(port)
@simple_layout('layouts/basic-pagure.yaml', driver='pagure')
def test_webhook(self):
A = self.fake_pagure.openFakePullRequest(
'org/project', 'master', 'A')
self.fake_pagure.emitEvent(A.getPullRequestOpenedEvent(),
use_zuulweb=True,
project='org/project',
wrong_token=True)
self.waitUntilSettled()
self.assertEqual(len(self.history), 0)
self.fake_pagure.emitEvent(A.getPullRequestOpenedEvent(),
use_zuulweb=True,
project='org/project')
self.waitUntilSettled()
self.assertEqual('SUCCESS',
self.getJobFromHistory('project-test1').result)
self.assertEqual('SUCCESS',
self.getJobFromHistory('project-test2').result)
class TestPagureWebhookWhitelist(ZuulTestCase):
config_file = 'zuul-pagure-driver-whitelist.conf'
def setUp(self):
super(TestPagureWebhookWhitelist, self).setUp()
# Start the web server
self.web = self.useFixture(
ZuulWebFixture(self.config, self.test_config,
self.additional_event_queues, self.upstream_root,
self.poller_events,
self.git_url_with_auth, self.addCleanup,
self.test_root))
host = '127.0.0.1'
# Wait until web server is started
while True:
port = self.web.port
try:
with socket.create_connection((host, port)):
break
except ConnectionRefusedError:
pass
self.fake_pagure.setZuulWebPort(port)
@simple_layout('layouts/basic-pagure.yaml', driver='pagure')
def test_webhook_whitelist(self):
A = self.fake_pagure.openFakePullRequest(
'org/project', 'master', 'A')
self.fake_pagure.emitEvent(A.getPullRequestOpenedEvent(),
use_zuulweb=True,
project='org/project',
wrong_token=True)
self.waitUntilSettled()
self.assertEqual('SUCCESS',
self.getJobFromHistory('project-test1').result)
self.assertEqual('SUCCESS',
self.getJobFromHistory('project-test2').result)