The Gatekeeper, or a project gating system
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

1128 lines
42 KiB

  1. # Copyright 2019 Red Hat
  2. #
  3. # Licensed under the Apache License, Version 2.0 (the "License"); you may
  4. # not use this file except in compliance with the License. You may obtain
  5. # a copy of the License at
  6. #
  7. # http://www.apache.org/licenses/LICENSE-2.0
  8. #
  9. # Unless required by applicable law or agreed to in writing, software
  10. # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  11. # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  12. # License for the specific language governing permissions and limitations
  13. # under the License.
  14. import os
  15. import re
  16. import git
  17. import yaml
  18. import socket
  19. from testtools.matchers import MatchesRegex
  20. import zuul.rpcclient
  21. from tests.base import ZuulTestCase, simple_layout
  22. from tests.base import ZuulWebFixture
  23. class TestPagureDriver(ZuulTestCase):
  24. config_file = 'zuul-pagure-driver.conf'
  25. @simple_layout('layouts/basic-pagure.yaml', driver='pagure')
  26. def test_pull_request_opened(self):
  27. initial_comment = "This is the\nPR initial_comment."
  28. A = self.fake_pagure.openFakePullRequest(
  29. 'org/project', 'master', 'A', initial_comment=initial_comment)
  30. self.fake_pagure.emitEvent(A.getPullRequestOpenedEvent())
  31. self.waitUntilSettled()
  32. self.assertEqual('SUCCESS',
  33. self.getJobFromHistory('project-test1').result)
  34. self.assertEqual('SUCCESS',
  35. self.getJobFromHistory('project-test2').result)
  36. job = self.getJobFromHistory('project-test2')
  37. zuulvars = job.parameters['zuul']
  38. self.assertEqual(str(A.number), zuulvars['change'])
  39. self.assertEqual(str(A.commit_stop), zuulvars['patchset'])
  40. self.assertEqual('master', zuulvars['branch'])
  41. self.assertEquals('https://pagure/org/project/pull-request/1',
  42. zuulvars['items'][0]['change_url'])
  43. self.assertEqual(zuulvars["message"], initial_comment)
  44. self.assertEqual(2, len(self.history))
  45. self.assertEqual(2, len(A.comments))
  46. self.assertEqual(
  47. A.comments[0]['comment'], "Starting check jobs.")
  48. self.assertThat(
  49. A.comments[1]['comment'],
  50. MatchesRegex(r'.*\[project-test1 \]\(.*\).*', re.DOTALL))
  51. self.assertThat(
  52. A.comments[1]['comment'],
  53. MatchesRegex(r'.*\[project-test2 \]\(.*\).*', re.DOTALL))
  54. self.assertEqual(1, len(A.flags))
  55. self.assertEqual('success', A.flags[0]['status'])
  56. @simple_layout('layouts/basic-pagure.yaml', driver='pagure')
  57. def test_pull_request_updated(self):
  58. A = self.fake_pagure.openFakePullRequest('org/project', 'master', 'A')
  59. pr_tip1 = A.commit_stop
  60. self.fake_pagure.emitEvent(A.getPullRequestOpenedEvent())
  61. self.waitUntilSettled()
  62. self.assertEqual(2, len(self.history))
  63. self.assertHistory(
  64. [
  65. {'name': 'project-test1', 'changes': '1,%s' % pr_tip1},
  66. {'name': 'project-test2', 'changes': '1,%s' % pr_tip1},
  67. ], ordered=False
  68. )
  69. self.fake_pagure.emitEvent(A.getPullRequestUpdatedEvent())
  70. pr_tip2 = A.commit_stop
  71. self.waitUntilSettled()
  72. self.assertEqual(4, len(self.history))
  73. self.assertHistory(
  74. [
  75. {'name': 'project-test1', 'changes': '1,%s' % pr_tip1},
  76. {'name': 'project-test2', 'changes': '1,%s' % pr_tip1},
  77. {'name': 'project-test1', 'changes': '1,%s' % pr_tip2},
  78. {'name': 'project-test2', 'changes': '1,%s' % pr_tip2}
  79. ], ordered=False
  80. )
  81. @simple_layout('layouts/basic-pagure.yaml', driver='pagure')
  82. def test_pull_request_updated_builds_aborted(self):
  83. A = self.fake_pagure.openFakePullRequest('org/project', 'master', 'A')
  84. pr_tip1 = A.commit_stop
  85. self.executor_server.hold_jobs_in_build = True
  86. self.fake_pagure.emitEvent(A.getPullRequestOpenedEvent())
  87. self.waitUntilSettled()
  88. self.fake_pagure.emitEvent(A.getPullRequestUpdatedEvent())
  89. pr_tip2 = A.commit_stop
  90. self.waitUntilSettled()
  91. self.executor_server.hold_jobs_in_build = False
  92. self.executor_server.release()
  93. self.waitUntilSettled()
  94. self.assertHistory(
  95. [
  96. {'name': 'project-test1', 'result': 'ABORTED',
  97. 'changes': '1,%s' % pr_tip1},
  98. {'name': 'project-test2', 'result': 'ABORTED',
  99. 'changes': '1,%s' % pr_tip1},
  100. {'name': 'project-test1', 'changes': '1,%s' % pr_tip2},
  101. {'name': 'project-test2', 'changes': '1,%s' % pr_tip2}
  102. ], ordered=False
  103. )
  104. @simple_layout('layouts/basic-pagure.yaml', driver='pagure')
  105. def test_pull_request_commented(self):
  106. A = self.fake_pagure.openFakePullRequest('org/project', 'master', 'A')
  107. self.fake_pagure.emitEvent(A.getPullRequestOpenedEvent())
  108. self.waitUntilSettled()
  109. self.assertEqual(2, len(self.history))
  110. self.fake_pagure.emitEvent(
  111. A.getPullRequestCommentedEvent('I like that change'))
  112. self.waitUntilSettled()
  113. self.assertEqual(2, len(self.history))
  114. self.fake_pagure.emitEvent(
  115. A.getPullRequestCommentedEvent('recheck'))
  116. self.waitUntilSettled()
  117. self.assertEqual(4, len(self.history))
  118. self.fake_pagure.emitEvent(
  119. A.getPullRequestInitialCommentEvent('Initial comment edited'))
  120. self.waitUntilSettled()
  121. self.assertEqual(6, len(self.history))
  122. @simple_layout('layouts/basic-pagure.yaml', driver='pagure')
  123. def test_pull_request_with_dyn_reconf(self):
  124. zuul_yaml = [
  125. {'job': {
  126. 'name': 'project-test3',
  127. 'run': 'job.yaml'
  128. }},
  129. {'project': {
  130. 'check': {
  131. 'jobs': [
  132. 'project-test3'
  133. ]
  134. }
  135. }}
  136. ]
  137. playbook = "- hosts: all\n tasks: []"
  138. A = self.fake_pagure.openFakePullRequest(
  139. 'org/project', 'master', 'A')
  140. A.addCommit(
  141. {'.zuul.yaml': yaml.dump(zuul_yaml),
  142. 'job.yaml': playbook}
  143. )
  144. self.fake_pagure.emitEvent(A.getPullRequestOpenedEvent())
  145. self.waitUntilSettled()
  146. self.assertEqual('SUCCESS',
  147. self.getJobFromHistory('project-test1').result)
  148. self.assertEqual('SUCCESS',
  149. self.getJobFromHistory('project-test2').result)
  150. self.assertEqual('SUCCESS',
  151. self.getJobFromHistory('project-test3').result)
  152. @simple_layout('layouts/basic-pagure.yaml', driver='pagure')
  153. def test_ref_updated(self):
  154. event = self.fake_pagure.getGitReceiveEvent('org/project')
  155. expected_newrev = event[1]['msg']['end_commit']
  156. expected_oldrev = event[1]['msg']['old_commit']
  157. self.fake_pagure.emitEvent(event)
  158. self.waitUntilSettled()
  159. self.assertEqual(1, len(self.history))
  160. self.assertEqual(
  161. 'SUCCESS',
  162. self.getJobFromHistory('project-post-job').result)
  163. job = self.getJobFromHistory('project-post-job')
  164. zuulvars = job.parameters['zuul']
  165. self.assertEqual('refs/heads/master', zuulvars['ref'])
  166. self.assertEqual('post', zuulvars['pipeline'])
  167. self.assertEqual('project-post-job', zuulvars['job'])
  168. self.assertEqual('master', zuulvars['branch'])
  169. self.assertEqual(
  170. 'https://pagure/org/project/c/%s' % zuulvars['newrev'],
  171. zuulvars['change_url'])
  172. self.assertEqual(expected_newrev, zuulvars['newrev'])
  173. self.assertEqual(expected_oldrev, zuulvars['oldrev'])
  174. @simple_layout('layouts/basic-pagure.yaml', driver='pagure')
  175. def test_ref_created(self):
  176. self.create_branch('org/project', 'stable-1.0')
  177. path = os.path.join(self.upstream_root, 'org/project')
  178. repo = git.Repo(path)
  179. newrev = repo.commit('refs/heads/stable-1.0').hexsha
  180. event = self.fake_pagure.getGitBranchEvent(
  181. 'org/project', 'stable-1.0', 'creation', newrev)
  182. old = self.scheds.first.sched.tenant_last_reconfigured\
  183. .get('tenant-one', 0)
  184. self.fake_pagure.emitEvent(event)
  185. self.waitUntilSettled()
  186. new = self.scheds.first.sched.tenant_last_reconfigured\
  187. .get('tenant-one', 0)
  188. # New timestamp should be greater than the old timestamp
  189. self.assertLess(old, new)
  190. self.assertEqual(1, len(self.history))
  191. self.assertEqual(
  192. 'SUCCESS',
  193. self.getJobFromHistory('project-post-job').result)
  194. job = self.getJobFromHistory('project-post-job')
  195. zuulvars = job.parameters['zuul']
  196. self.assertEqual('refs/heads/stable-1.0', zuulvars['ref'])
  197. self.assertEqual('post', zuulvars['pipeline'])
  198. self.assertEqual('project-post-job', zuulvars['job'])
  199. self.assertEqual('stable-1.0', zuulvars['branch'])
  200. self.assertEqual(newrev, zuulvars['newrev'])
  201. @simple_layout('layouts/basic-pagure.yaml', driver='pagure')
  202. def test_ref_deleted(self):
  203. event = self.fake_pagure.getGitBranchEvent(
  204. 'org/project', 'stable-1.0', 'deletion', '0' * 40)
  205. self.fake_pagure.emitEvent(event)
  206. self.waitUntilSettled()
  207. self.assertEqual(0, len(self.history))
  208. @simple_layout('layouts/basic-pagure.yaml', driver='pagure')
  209. def test_ref_updated_and_tenant_reconfigure(self):
  210. self.waitUntilSettled()
  211. old = self.scheds.first.sched.tenant_last_reconfigured\
  212. .get('tenant-one', 0)
  213. zuul_yaml = [
  214. {'job': {
  215. 'name': 'project-post-job2',
  216. 'run': 'job.yaml'
  217. }},
  218. {'project': {
  219. 'post': {
  220. 'jobs': [
  221. 'project-post-job2'
  222. ]
  223. }
  224. }}
  225. ]
  226. playbook = "- hosts: all\n tasks: []"
  227. self.create_commit(
  228. 'org/project',
  229. {'.zuul.yaml': yaml.dump(zuul_yaml),
  230. 'job.yaml': playbook},
  231. message='Add InRepo configuration'
  232. )
  233. event = self.fake_pagure.getGitReceiveEvent('org/project')
  234. self.fake_pagure.emitEvent(event)
  235. self.waitUntilSettled()
  236. new = self.scheds.first.sched.tenant_last_reconfigured\
  237. .get('tenant-one', 0)
  238. # New timestamp should be greater than the old timestamp
  239. self.assertLess(old, new)
  240. self.assertHistory(
  241. [{'name': 'project-post-job'},
  242. {'name': 'project-post-job2'},
  243. ], ordered=False
  244. )
  245. @simple_layout('layouts/files-pagure.yaml', driver='pagure')
  246. def test_pull_matched_file_event(self):
  247. A = self.fake_pagure.openFakePullRequest(
  248. 'org/project', 'master', 'A',
  249. files={'random.txt': 'test', 'build-requires': 'test'})
  250. self.fake_pagure.emitEvent(A.getPullRequestOpenedEvent())
  251. self.waitUntilSettled()
  252. self.assertEqual(1, len(self.history))
  253. B = self.fake_pagure.openFakePullRequest('org/project', 'master', 'B',
  254. files={'random.txt': 'test2'})
  255. self.fake_pagure.emitEvent(B.getPullRequestOpenedEvent())
  256. self.waitUntilSettled()
  257. self.assertEqual(1, len(self.history))
  258. C = self.fake_pagure.openFakePullRequest(
  259. 'org/project', 'master', 'C',
  260. files={'build-requires': 'test'})
  261. self.fake_pagure.emitEvent(C.getPullRequestOpenedEvent())
  262. self.waitUntilSettled()
  263. self.assertEqual(2, len(self.history))
  264. @simple_layout('layouts/basic-pagure.yaml', driver='pagure')
  265. def test_tag_created(self):
  266. path = os.path.join(self.upstream_root, 'org/project')
  267. repo = git.Repo(path)
  268. repo.create_tag('1.0')
  269. tagsha = repo.tags['1.0'].commit.hexsha
  270. event = self.fake_pagure.getGitTagCreatedEvent(
  271. 'org/project', '1.0', tagsha)
  272. self.fake_pagure.emitEvent(event)
  273. self.waitUntilSettled()
  274. self.assertEqual(1, len(self.history))
  275. self.assertEqual(
  276. 'SUCCESS',
  277. self.getJobFromHistory('project-tag-job').result)
  278. job = self.getJobFromHistory('project-tag-job')
  279. zuulvars = job.parameters['zuul']
  280. self.assertEqual('refs/tags/1.0', zuulvars['ref'])
  281. self.assertEqual('tag', zuulvars['pipeline'])
  282. self.assertEqual('project-tag-job', zuulvars['job'])
  283. self.assertEqual(tagsha, zuulvars['newrev'])
  284. @simple_layout('layouts/basic-pagure.yaml', driver='pagure')
  285. def test_client_dequeue_change_pagure(self):
  286. client = zuul.rpcclient.RPCClient('127.0.0.1',
  287. self.gearman_server.port)
  288. self.addCleanup(client.shutdown)
  289. self.executor_server.hold_jobs_in_build = True
  290. A = self.fake_pagure.openFakePullRequest('org/project', 'master', 'A')
  291. self.fake_pagure.emitEvent(A.getPullRequestOpenedEvent())
  292. self.waitUntilSettled()
  293. client.dequeue(
  294. tenant='tenant-one',
  295. pipeline='check',
  296. project='org/project',
  297. change='%s,%s' % (A.number, A.commit_stop),
  298. ref=None)
  299. self.waitUntilSettled()
  300. tenant = self.scheds.first.sched.abide.tenants.get('tenant-one')
  301. check_pipeline = tenant.layout.pipelines['check']
  302. self.assertEqual(check_pipeline.getAllItems(), [])
  303. self.assertEqual(self.countJobResults(self.history, 'ABORTED'), 2)
  304. self.executor_server.hold_jobs_in_build = False
  305. self.executor_server.release()
  306. self.waitUntilSettled()
  307. @simple_layout('layouts/basic-pagure.yaml', driver='pagure')
  308. def test_client_enqueue_change_pagure(self):
  309. A = self.fake_pagure.openFakePullRequest('org/project', 'master', 'A')
  310. client = zuul.rpcclient.RPCClient('127.0.0.1',
  311. self.gearman_server.port)
  312. self.addCleanup(client.shutdown)
  313. r = client.enqueue(tenant='tenant-one',
  314. pipeline='check',
  315. project='org/project',
  316. trigger='pagure',
  317. change='%s,%s' % (A.number, A.commit_stop))
  318. self.waitUntilSettled()
  319. self.assertEqual(self.getJobFromHistory('project-test1').result,
  320. 'SUCCESS')
  321. self.assertEqual(self.getJobFromHistory('project-test2').result,
  322. 'SUCCESS')
  323. self.assertEqual(r, True)
  324. @simple_layout('layouts/basic-pagure.yaml', driver='pagure')
  325. def test_client_enqueue_ref_pagure(self):
  326. repo_path = os.path.join(self.upstream_root, 'org/project')
  327. repo = git.Repo(repo_path)
  328. headsha = repo.head.commit.hexsha
  329. client = zuul.rpcclient.RPCClient('127.0.0.1',
  330. self.gearman_server.port)
  331. self.addCleanup(client.shutdown)
  332. r = client.enqueue_ref(
  333. tenant='tenant-one',
  334. pipeline='post',
  335. project='org/project',
  336. trigger='pagure',
  337. ref='master',
  338. oldrev='90f173846e3af9154517b88543ffbd1691f31366',
  339. newrev=headsha)
  340. self.waitUntilSettled()
  341. self.assertEqual(self.getJobFromHistory('project-post-job').result,
  342. 'SUCCESS')
  343. self.assertEqual(r, True)
  344. @simple_layout('layouts/requirements-pagure.yaml', driver='pagure')
  345. def test_pr_score_require_1_vote(self):
  346. A = self.fake_pagure.openFakePullRequest(
  347. 'org/project1', 'master', 'A')
  348. self.fake_pagure.emitEvent(
  349. A.getPullRequestCommentedEvent("I like that change"))
  350. self.waitUntilSettled()
  351. self.assertEqual(0, len(self.history))
  352. self.fake_pagure.emitEvent(
  353. A.getPullRequestCommentedEvent(":thumbsup:"))
  354. self.waitUntilSettled()
  355. self.assertEqual(1, len(self.history))
  356. self.assertEqual(
  357. 'SUCCESS',
  358. self.getJobFromHistory('project-test').result)
  359. @simple_layout('layouts/requirements-pagure.yaml', driver='pagure')
  360. def test_pr_score_require_2_votes(self):
  361. A = self.fake_pagure.openFakePullRequest(
  362. 'org/project2', 'master', 'A')
  363. self.fake_pagure.emitEvent(
  364. A.getPullRequestCommentedEvent("I like that change"))
  365. self.waitUntilSettled()
  366. self.assertEqual(0, len(self.history))
  367. self.fake_pagure.emitEvent(
  368. A.getPullRequestCommentedEvent(":thumbsup:"))
  369. self.waitUntilSettled()
  370. self.assertEqual(0, len(self.history))
  371. self.fake_pagure.emitEvent(
  372. A.getPullRequestCommentedEvent(":thumbsdown:"))
  373. self.waitUntilSettled()
  374. self.assertEqual(0, len(self.history))
  375. self.fake_pagure.emitEvent(
  376. A.getPullRequestCommentedEvent(":thumbsup:"))
  377. self.waitUntilSettled()
  378. self.assertEqual(0, len(self.history))
  379. self.fake_pagure.emitEvent(
  380. A.getPullRequestCommentedEvent(":thumbsup:"))
  381. self.waitUntilSettled()
  382. self.assertEqual(1, len(self.history))
  383. @simple_layout('layouts/requirements-pagure.yaml', driver='pagure')
  384. def test_status_trigger(self):
  385. A = self.fake_pagure.openFakePullRequest(
  386. 'org/project3', 'master', 'A')
  387. self.fake_pagure.emitEvent(
  388. A.getPullRequestStatusSetEvent("failure"))
  389. self.waitUntilSettled()
  390. self.assertEqual(0, len(self.history))
  391. self.fake_pagure.emitEvent(
  392. A.getPullRequestStatusSetEvent("success"))
  393. self.waitUntilSettled()
  394. self.assertEqual(1, len(self.history))
  395. @simple_layout('layouts/requirements-pagure.yaml', driver='pagure')
  396. def test_tag_trigger(self):
  397. A = self.fake_pagure.openFakePullRequest(
  398. 'org/project4', 'master', 'A')
  399. self.fake_pagure.emitEvent(
  400. A.getPullRequestTagAddedEvent(["lambda"]))
  401. self.waitUntilSettled()
  402. self.assertEqual(0, len(self.history))
  403. self.fake_pagure.emitEvent(
  404. A.getPullRequestTagAddedEvent(["gateit", "lambda"]))
  405. self.waitUntilSettled()
  406. self.assertEqual(1, len(self.history))
  407. self.fake_pagure.emitEvent(
  408. A.getPullRequestTagAddedEvent(["mergeit"]))
  409. self.waitUntilSettled()
  410. self.assertEqual(2, len(self.history))
  411. @simple_layout('layouts/requirements-pagure.yaml', driver='pagure')
  412. def test_tag_require(self):
  413. A = self.fake_pagure.openFakePullRequest(
  414. 'org/project5', 'master', 'A')
  415. self.fake_pagure.emitEvent(A.getPullRequestUpdatedEvent())
  416. self.waitUntilSettled()
  417. self.assertEqual(0, len(self.history))
  418. A.tags = ["lambda"]
  419. self.fake_pagure.emitEvent(A.getPullRequestUpdatedEvent())
  420. self.waitUntilSettled()
  421. self.assertEqual(0, len(self.history))
  422. A.tags = ["lambda", "gateit"]
  423. self.fake_pagure.emitEvent(A.getPullRequestUpdatedEvent())
  424. self.waitUntilSettled()
  425. self.assertEqual(1, len(self.history))
  426. A.tags = []
  427. self.fake_pagure.emitEvent(A.getPullRequestUpdatedEvent())
  428. self.waitUntilSettled()
  429. self.assertEqual(1, len(self.history))
  430. @simple_layout('layouts/requirements-pagure.yaml', driver='pagure')
  431. def test_flag_require(self):
  432. A = self.fake_pagure.openFakePullRequest(
  433. 'org/project7', 'master', 'A')
  434. # CI status from other CIs must not be handled
  435. self.fake_pagure.emitEvent(
  436. A.getPullRequestStatusSetEvent("success", username="notzuul"))
  437. self.waitUntilSettled()
  438. self.assertEqual(0, len(self.history))
  439. self.assertEqual(1, len(A.flags))
  440. self.fake_pagure.emitEvent(
  441. A.getPullRequestStatusSetEvent("failure"))
  442. self.waitUntilSettled()
  443. self.assertEqual(0, len(self.history))
  444. self.assertEqual(2, len(A.flags))
  445. self.fake_pagure.emitEvent(
  446. A.getPullRequestStatusSetEvent("success"))
  447. self.waitUntilSettled()
  448. self.assertEqual(1, len(self.history))
  449. self.assertEqual(2, len(A.flags))
  450. @simple_layout('layouts/requirements-pagure.yaml', driver='pagure')
  451. def test_pull_request_closed(self):
  452. A = self.fake_pagure.openFakePullRequest(
  453. 'org/project6', 'master', 'A')
  454. self.fake_pagure.emitEvent(A.getPullRequestOpenedEvent())
  455. self.waitUntilSettled()
  456. self.assertEqual(0, len(self.history))
  457. # Validate a closed but not merged PR does not trigger the pipeline
  458. self.fake_pagure.emitEvent(A.getPullRequestClosedEvent(merged=False))
  459. self.waitUntilSettled()
  460. self.assertEqual(0, len(self.history))
  461. # Reset the status to Open
  462. # Validate a closed and merged PR triggers the pipeline
  463. A.status = 'Open'
  464. A.is_merged = False
  465. self.fake_pagure.emitEvent(A.getPullRequestClosedEvent())
  466. self.waitUntilSettled()
  467. self.assertEqual(1, len(self.history))
  468. @simple_layout('layouts/merging-pagure.yaml', driver='pagure')
  469. def test_merge_action_in_independent(self):
  470. A = self.fake_pagure.openFakePullRequest(
  471. 'org/project1', 'master', 'A')
  472. self.fake_pagure.emitEvent(A.getPullRequestOpenedEvent())
  473. self.waitUntilSettled()
  474. self.assertEqual(1, len(self.history))
  475. self.assertEqual('SUCCESS',
  476. self.getJobFromHistory('project-test').result)
  477. self.assertEqual('Merged', A.status)
  478. @simple_layout('layouts/merging-pagure.yaml', driver='pagure')
  479. def test_merge_action_in_dependent(self):
  480. A = self.fake_pagure.openFakePullRequest(
  481. 'org/project2', 'master', 'A')
  482. self.fake_pagure.emitEvent(A.getPullRequestOpenedEvent())
  483. self.waitUntilSettled()
  484. # connection.canMerge is not validated
  485. self.assertEqual(0, len(self.history))
  486. # Set the mergeable PR flag to a expected value
  487. A.cached_merge_status = 'MERGE'
  488. self.fake_pagure.emitEvent(A.getPullRequestOpenedEvent())
  489. self.waitUntilSettled()
  490. # connection.canMerge is not validated
  491. self.assertEqual(0, len(self.history))
  492. # Set the score threshold as reached
  493. # Here we use None that means no specific score is required
  494. A.threshold_reached = None
  495. self.fake_pagure.emitEvent(A.getPullRequestOpenedEvent())
  496. self.waitUntilSettled()
  497. # connection.canMerge is not validated
  498. self.assertEqual(0, len(self.history))
  499. # Set CI flag as passed CI
  500. A.addFlag('success', 'https://url', 'Build passed')
  501. self.fake_pagure.emitEvent(A.getPullRequestOpenedEvent())
  502. self.waitUntilSettled()
  503. # connection.canMerge is validated
  504. self.assertEqual(1, len(self.history))
  505. self.assertEqual('SUCCESS',
  506. self.getJobFromHistory('project-test').result)
  507. self.assertEqual('Merged', A.status)
  508. @simple_layout('layouts/crd-pagure.yaml', driver='pagure')
  509. def test_crd_independent(self):
  510. # Create a change in project1 that a project2 change will depend on
  511. A = self.fake_pagure.openFakePullRequest('org/project1', 'master', 'A')
  512. # Create a commit in B that sets the dependency on A
  513. msg = "Depends-On: %s" % A.url
  514. B = self.fake_pagure.openFakePullRequest(
  515. 'org/project2', 'master', 'B', initial_comment=msg)
  516. # Make an event to re-use
  517. event = B.getPullRequestCommentedEvent('A comment')
  518. self.fake_pagure.emitEvent(event)
  519. self.waitUntilSettled()
  520. # The changes for the job from project2 should include the project1
  521. # PR content
  522. changes = self.getJobFromHistory(
  523. 'project2-test', 'org/project2').changes
  524. self.assertEqual(changes, "%s,%s %s,%s" % (A.number,
  525. A.commit_stop,
  526. B.number,
  527. B.commit_stop))
  528. # There should be no more changes in the queue
  529. tenant = self.scheds.first.sched.abide.tenants.get('tenant-one')
  530. self.assertEqual(len(tenant.layout.pipelines['check'].queues), 0)
  531. @simple_layout('layouts/crd-pagure.yaml', driver='pagure')
  532. def test_crd_dependent(self):
  533. # Create a change in project3 that a project4 change will depend on
  534. A = self.fake_pagure.openFakePullRequest('org/project3', 'master', 'A')
  535. # Create a commit in B that sets the dependency on A
  536. msg = "Depends-On: %s" % A.url
  537. B = self.fake_pagure.openFakePullRequest(
  538. 'org/project4', 'master', 'B', initial_comment=msg)
  539. # Make an event to re-use
  540. event = B.getPullRequestCommentedEvent('A comment')
  541. self.fake_pagure.emitEvent(event)
  542. self.waitUntilSettled()
  543. # Neither A and B can't merge (no flag, no score threshold)
  544. self.assertEqual(0, len(self.history))
  545. B.threshold_reached = True
  546. B.addFlag('success', 'https://url', 'Build passed')
  547. self.fake_pagure.emitEvent(event)
  548. self.waitUntilSettled()
  549. # B can't merge as A got no flag, no score threshold
  550. self.assertEqual(0, len(self.history))
  551. A.threshold_reached = True
  552. A.addFlag('success', 'https://url', 'Build passed')
  553. self.fake_pagure.emitEvent(event)
  554. self.waitUntilSettled()
  555. # The changes for the job from project4 should include the project3
  556. # PR content
  557. changes = self.getJobFromHistory(
  558. 'project4-test', 'org/project4').changes
  559. self.assertEqual(changes, "%s,%s %s,%s" % (A.number,
  560. A.commit_stop,
  561. B.number,
  562. B.commit_stop))
  563. self.assertTrue(A.is_merged)
  564. self.assertTrue(B.is_merged)
  565. @simple_layout('layouts/crd-pagure.yaml', driver='pagure')
  566. def test_crd_needed_changes(self):
  567. # Given change A and B, where B depends on A, when A
  568. # completes B should be enqueued (using a shared queue)
  569. # Create a change in project3 that a project4 change will depend on
  570. A = self.fake_pagure.openFakePullRequest('org/project3', 'master', 'A')
  571. A.threshold_reached = True
  572. A.addFlag('success', 'https://url', 'Build passed')
  573. # Set B to depend on A
  574. msg = "Depends-On: %s" % A.url
  575. B = self.fake_pagure.openFakePullRequest(
  576. 'org/project4', 'master', 'B', initial_comment=msg)
  577. # Make the driver aware of change B by sending an event
  578. # At that moment B can't merge
  579. self.fake_pagure.emitEvent(B.getPullRequestCommentedEvent('A comment'))
  580. # Now set B mergeable
  581. B.threshold_reached = True
  582. B.addFlag('success', 'https://url', 'Build passed')
  583. # Enqueue A, which will make the scheduler detect that B is
  584. # depending on so B will be enqueue as well.
  585. self.fake_pagure.emitEvent(A.getPullRequestCommentedEvent('A comment'))
  586. self.waitUntilSettled()
  587. # The changes for the job from project4 should include the project3
  588. # PR content
  589. changes = self.getJobFromHistory(
  590. 'project4-test', 'org/project4').changes
  591. self.assertEqual(changes, "%s,%s %s,%s" % (A.number,
  592. A.commit_stop,
  593. B.number,
  594. B.commit_stop))
  595. self.assertTrue(A.is_merged)
  596. self.assertTrue(B.is_merged)
  597. class TestPagureToGerritCRD(ZuulTestCase):
  598. config_file = 'zuul-crd-pagure.conf'
  599. tenant_config_file = 'config/cross-source-pagure/gerrit.yaml'
  600. def test_crd_gate(self):
  601. "Test cross-repo dependencies"
  602. A = self.fake_pagure.openFakePullRequest('pagure/project2', 'master',
  603. 'A')
  604. B = self.fake_gerrit.addFakeChange('gerrit/project1', 'master', 'B')
  605. # A Depends-On: B
  606. A.editInitialComment('Depends-On: %s\n' % (B.data['url']))
  607. A.addFlag('success', 'https://url', 'Build passed')
  608. A.threshold_reached = True
  609. B.addApproval('Code-Review', 2)
  610. # Make A enter the pipeline
  611. self.fake_pagure.emitEvent(
  612. A.getPullRequestCommentedEvent(":thumbsup:"))
  613. self.waitUntilSettled()
  614. # Expect not merged as B not approved yet
  615. self.assertFalse(A.is_merged)
  616. self.assertEqual(B.data['status'], 'NEW')
  617. for connection in self.scheds.first.connections.connections.values():
  618. connection.maintainCache([])
  619. B.addApproval('Approved', 1)
  620. self.fake_pagure.emitEvent(
  621. A.getPullRequestCommentedEvent(":thumbsup:"))
  622. self.waitUntilSettled()
  623. self.assertTrue(A.is_merged)
  624. self.assertEqual(B.data['status'], 'MERGED')
  625. self.assertEqual(len(A.comments), 4)
  626. self.assertEqual(B.reported, 2)
  627. changes = self.getJobFromHistory(
  628. 'project-merge', 'pagure/project2').changes
  629. self.assertEqual(changes, '1,1 1,%s' % A.commit_stop)
  630. def test_crd_check(self):
  631. "Test cross-repo dependencies in independent pipelines"
  632. A = self.fake_pagure.openFakePullRequest('pagure/project2', 'master',
  633. 'A')
  634. B = self.fake_gerrit.addFakeChange(
  635. 'gerrit/project1', 'master', 'B')
  636. # A Depends-On: B
  637. A.editInitialComment('Depends-On: %s\n' % (B.data['url'],))
  638. self.executor_server.hold_jobs_in_build = True
  639. self.fake_pagure.emitEvent(A.getPullRequestUpdatedEvent())
  640. self.waitUntilSettled()
  641. self.assertTrue(self.builds[0].hasChanges(A, B))
  642. self.executor_server.hold_jobs_in_build = False
  643. self.executor_server.release()
  644. self.waitUntilSettled()
  645. self.assertFalse(A.is_merged)
  646. self.assertEqual(B.data['status'], 'NEW')
  647. self.assertEqual(len(A.comments), 2)
  648. self.assertEqual(B.reported, 0)
  649. changes = self.getJobFromHistory(
  650. 'project-merge', 'pagure/project2').changes
  651. self.assertEqual(changes, '1,1 1,%s' % A.commit_stop)
  652. class TestGerritToPagureCRD(ZuulTestCase):
  653. config_file = 'zuul-crd-pagure.conf'
  654. tenant_config_file = 'config/cross-source-pagure/gerrit.yaml'
  655. def test_crd_gate(self):
  656. "Test cross-repo dependencies"
  657. A = self.fake_gerrit.addFakeChange('gerrit/project1', 'master', 'A')
  658. B = self.fake_pagure.openFakePullRequest('pagure/project2', 'master',
  659. 'B')
  660. A.addApproval('Code-Review', 2)
  661. AM2 = self.fake_gerrit.addFakeChange('gerrit/project1', 'master',
  662. 'AM2')
  663. AM1 = self.fake_gerrit.addFakeChange('gerrit/project1', 'master',
  664. 'AM1')
  665. AM2.setMerged()
  666. AM1.setMerged()
  667. # A -> AM1 -> AM2
  668. # A Depends-On: B
  669. # M2 is here to make sure it is never queried. If it is, it
  670. # means zuul is walking down the entire history of merged
  671. # changes.
  672. A.setDependsOn(AM1, 1)
  673. AM1.setDependsOn(AM2, 1)
  674. A.data['commitMessage'] = '%s\n\nDepends-On: %s\n' % (
  675. A.subject, B.url)
  676. self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
  677. self.waitUntilSettled()
  678. self.assertEqual(A.data['status'], 'NEW')
  679. self.assertFalse(B.is_merged)
  680. for connection in self.scheds.first.connections.connections.values():
  681. connection.maintainCache([])
  682. B.addFlag('success', 'https://url', 'Build passed')
  683. B.threshold_reached = True
  684. self.fake_pagure.emitEvent(
  685. B.getPullRequestCommentedEvent(":thumbsup:"))
  686. self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
  687. self.waitUntilSettled()
  688. self.assertEqual(AM2.queried, 0)
  689. self.assertEqual(A.data['status'], 'MERGED')
  690. self.assertTrue(B.is_merged)
  691. self.assertEqual(A.reported, 2)
  692. self.assertEqual(len(B.comments), 3)
  693. changes = self.getJobFromHistory(
  694. 'project-merge', 'gerrit/project1').changes
  695. self.assertEqual(changes, '1,%s 1,1' % B.commit_stop)
  696. def test_crd_check(self):
  697. "Test cross-repo dependencies in independent pipelines"
  698. A = self.fake_gerrit.addFakeChange('gerrit/project1', 'master', 'A')
  699. B = self.fake_pagure.openFakePullRequest(
  700. 'pagure/project2', 'master', 'B')
  701. # A Depends-On: B
  702. A.data['commitMessage'] = '%s\n\nDepends-On: %s\n' % (
  703. A.subject, B.url)
  704. self.executor_server.hold_jobs_in_build = True
  705. self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
  706. self.waitUntilSettled()
  707. self.assertTrue(self.builds[0].hasChanges(A, B))
  708. self.executor_server.hold_jobs_in_build = False
  709. self.executor_server.release()
  710. self.waitUntilSettled()
  711. self.assertEqual(A.data['status'], 'NEW')
  712. self.assertFalse(B.is_merged)
  713. self.assertEqual(A.reported, 1)
  714. self.assertEqual(len(B.comments), 0)
  715. changes = self.getJobFromHistory(
  716. 'project-merge', 'gerrit/project1').changes
  717. self.assertEqual(changes, '1,%s 1,1' % B.commit_stop)
  718. class TestPagureToGithubCRD(ZuulTestCase):
  719. config_file = 'zuul-crd-pagure.conf'
  720. tenant_config_file = 'config/cross-source-pagure/github.yaml'
  721. def test_crd_gate(self):
  722. "Test cross-repo dependencies"
  723. A = self.fake_pagure.openFakePullRequest('pagure/project2', 'master',
  724. 'A')
  725. B = self.fake_github.openFakePullRequest('github/project1', 'master',
  726. 'B')
  727. # A Depends-On: B
  728. A.editInitialComment('Depends-On: %s\n' % (B.url))
  729. A.addFlag('success', 'https://url', 'Build passed')
  730. A.threshold_reached = True
  731. # Make A enter the pipeline
  732. self.fake_pagure.emitEvent(
  733. A.getPullRequestCommentedEvent(":thumbsup:"))
  734. self.waitUntilSettled()
  735. # Expect not merged as B not approved yet
  736. self.assertFalse(A.is_merged)
  737. self.assertFalse(B.is_merged)
  738. for connection in self.scheds.first.connections.connections.values():
  739. connection.maintainCache([])
  740. B.addLabel('approved')
  741. self.fake_pagure.emitEvent(
  742. A.getPullRequestCommentedEvent(":thumbsup:"))
  743. self.waitUntilSettled()
  744. self.assertTrue(A.is_merged)
  745. self.assertTrue(B.is_merged)
  746. self.assertEqual(len(A.comments), 4)
  747. self.assertEqual(len(B.comments), 2)
  748. changes = self.getJobFromHistory(
  749. 'project-merge', 'pagure/project2').changes
  750. self.assertEqual(changes, '1,%s 1,%s' % (B.head_sha, A.commit_stop))
  751. def test_crd_check(self):
  752. "Test cross-repo dependencies in independent pipelines"
  753. A = self.fake_pagure.openFakePullRequest('pagure/project2', 'master',
  754. 'A')
  755. B = self.fake_github.openFakePullRequest('github/project1', 'master',
  756. 'A')
  757. # A Depends-On: B
  758. A.editInitialComment('Depends-On: %s\n' % B.url)
  759. self.executor_server.hold_jobs_in_build = True
  760. self.fake_pagure.emitEvent(A.getPullRequestUpdatedEvent())
  761. self.waitUntilSettled()
  762. self.assertTrue(self.builds[0].hasChanges(A, B))
  763. self.executor_server.hold_jobs_in_build = False
  764. self.executor_server.release()
  765. self.waitUntilSettled()
  766. self.assertFalse(A.is_merged)
  767. self.assertFalse(B.is_merged)
  768. self.assertEqual(len(A.comments), 2)
  769. self.assertEqual(len(A.comments), 2)
  770. changes = self.getJobFromHistory(
  771. 'project-merge', 'pagure/project2').changes
  772. self.assertEqual(changes, '1,%s 1,%s' % (B.head_sha, A.commit_stop))
  773. class TestGithubToPagureCRD(ZuulTestCase):
  774. config_file = 'zuul-crd-pagure.conf'
  775. tenant_config_file = 'config/cross-source-pagure/github.yaml'
  776. def test_crd_gate(self):
  777. "Test cross-repo dependencies"
  778. A = self.fake_github.openFakePullRequest('github/project1', 'master',
  779. 'A')
  780. B = self.fake_pagure.openFakePullRequest('pagure/project2', 'master',
  781. 'B')
  782. # A Depends-On: B
  783. A.editBody('Depends-On: %s\n' % B.url)
  784. event = A.addLabel('approved')
  785. self.fake_github.emitEvent(event)
  786. self.waitUntilSettled()
  787. self.assertFalse(A.is_merged)
  788. self.assertFalse(B.is_merged)
  789. for connection in self.scheds.first.connections.connections.values():
  790. connection.maintainCache([])
  791. B.addFlag('success', 'https://url', 'Build passed')
  792. B.threshold_reached = True
  793. self.fake_pagure.emitEvent(
  794. B.getPullRequestCommentedEvent(":thumbsup:"))
  795. self.fake_github.emitEvent(event)
  796. self.waitUntilSettled()
  797. self.assertTrue(A.is_merged)
  798. self.assertTrue(B.is_merged)
  799. self.assertEqual(len(A.comments), 2)
  800. self.assertEqual(len(B.comments), 3)
  801. changes = self.getJobFromHistory(
  802. 'project-merge', 'github/project1').changes
  803. self.assertEqual(changes, '1,%s 1,%s' % (B.commit_stop, A.head_sha))
  804. def test_crd_check(self):
  805. "Test cross-repo dependencies in independent pipelines"
  806. A = self.fake_github.openFakePullRequest(
  807. 'github/project1', 'master', 'A')
  808. B = self.fake_pagure.openFakePullRequest(
  809. 'pagure/project2', 'master', 'B')
  810. # A Depends-On: B
  811. A.editBody('Depends-On: %s\n' % B.url)
  812. self.executor_server.hold_jobs_in_build = True
  813. self.fake_github.emitEvent(A.getPullRequestEditedEvent())
  814. self.waitUntilSettled()
  815. self.assertTrue(self.builds[0].hasChanges(A, B))
  816. self.executor_server.hold_jobs_in_build = False
  817. self.executor_server.release()
  818. self.waitUntilSettled()
  819. self.assertFalse(A.is_merged)
  820. self.assertFalse(B.is_merged)
  821. self.assertEqual(len(A.comments), 1)
  822. self.assertEqual(len(B.comments), 0)
  823. changes = self.getJobFromHistory(
  824. 'project-merge', 'github/project1').changes
  825. self.assertEqual(changes, '1,%s 1,%s' % (B.commit_stop, A.head_sha))
  826. class TestPagureWebhook(ZuulTestCase):
  827. config_file = 'zuul-pagure-driver.conf'
  828. def setUp(self):
  829. super(TestPagureWebhook, self).setUp()
  830. # Start the web server
  831. self.web = self.useFixture(
  832. ZuulWebFixture(self.gearman_server.port, self.changes, self.config,
  833. self.additional_event_queues, self.upstream_root,
  834. self.rpcclient, self.poller_events,
  835. self.git_url_with_auth, self.addCleanup,
  836. self.test_root))
  837. host = '127.0.0.1'
  838. # Wait until web server is started
  839. while True:
  840. port = self.web.port
  841. try:
  842. with socket.create_connection((host, port)):
  843. break
  844. except ConnectionRefusedError:
  845. pass
  846. self.fake_pagure.setZuulWebPort(port)
  847. @simple_layout('layouts/basic-pagure.yaml', driver='pagure')
  848. def test_webhook(self):
  849. A = self.fake_pagure.openFakePullRequest(
  850. 'org/project', 'master', 'A')
  851. self.fake_pagure.emitEvent(A.getPullRequestOpenedEvent(),
  852. use_zuulweb=True,
  853. project='org/project',
  854. wrong_token=True)
  855. self.waitUntilSettled()
  856. self.assertEqual(len(self.history), 0)
  857. self.fake_pagure.emitEvent(A.getPullRequestOpenedEvent(),
  858. use_zuulweb=True,
  859. project='org/project')
  860. self.waitUntilSettled()
  861. self.assertEqual('SUCCESS',
  862. self.getJobFromHistory('project-test1').result)
  863. self.assertEqual('SUCCESS',
  864. self.getJobFromHistory('project-test2').result)
  865. class TestPagureWebhookWhitelist(ZuulTestCase):
  866. config_file = 'zuul-pagure-driver-whitelist.conf'
  867. def setUp(self):
  868. super(TestPagureWebhookWhitelist, self).setUp()
  869. # Start the web server
  870. self.web = self.useFixture(
  871. ZuulWebFixture(self.gearman_server.port, self.changes, self.config,
  872. self.additional_event_queues, self.upstream_root,
  873. self.rpcclient, self.poller_events,
  874. self.git_url_with_auth, self.addCleanup,
  875. self.test_root))
  876. host = '127.0.0.1'
  877. # Wait until web server is started
  878. while True:
  879. port = self.web.port
  880. try:
  881. with socket.create_connection((host, port)):
  882. break
  883. except ConnectionRefusedError:
  884. pass
  885. self.fake_pagure.setZuulWebPort(port)
  886. @simple_layout('layouts/basic-pagure.yaml', driver='pagure')
  887. def test_webhook_whitelist(self):
  888. A = self.fake_pagure.openFakePullRequest(
  889. 'org/project', 'master', 'A')
  890. self.fake_pagure.emitEvent(A.getPullRequestOpenedEvent(),
  891. use_zuulweb=True,
  892. project='org/project',
  893. wrong_token=True)
  894. self.waitUntilSettled()
  895. self.assertEqual('SUCCESS',
  896. self.getJobFromHistory('project-test1').result)
  897. self.assertEqual('SUCCESS',
  898. self.getJobFromHistory('project-test2').result)