Add zuul-client testing
Define unit testing for the zuul-client CLI. The actual testing job will be defined in a subsequent patch to the zuul-client project. These tests are stored in the zuul repository rather than in zuul-client's because we rely on zuul's test framework to bootstrap zuul and zuul-web, which is not available through zuul's python package. This is similar to what is done for nodepool's functional testing with zuul. Change-Id: I156162279c5d638ef39d22fcfb043655890c2d6e Depends-On: https://review.opendev.org/751291
This commit is contained in:
parent
e4b2e2c0ef
commit
8b29c09f40
@ -2151,6 +2151,8 @@ class TestWebMulti(BaseTestWeb):
|
||||
self.assertEqual([gerrit_connection, github_connection], data)
|
||||
|
||||
|
||||
# TODO Remove this class once REST support is removed from Zuul CLI, or
|
||||
# switch to the gearman client
|
||||
class TestCLIViaWebApi(BaseTestWeb):
|
||||
config_file = 'zuul-admin-web.conf'
|
||||
|
||||
|
0
tests/zuul_client/__init__.py
Normal file
0
tests/zuul_client/__init__.py
Normal file
268
tests/zuul_client/test_zuulclient.py
Normal file
268
tests/zuul_client/test_zuulclient.py
Normal file
@ -0,0 +1,268 @@
|
||||
# Copyright 2020 Red Hat, inc.
|
||||
#
|
||||
# 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 time
|
||||
import jwt
|
||||
import subprocess
|
||||
|
||||
import zuul.web
|
||||
import zuul.rpcclient
|
||||
|
||||
from tests.base import iterate_timeout
|
||||
from tests.unit.test_web import BaseTestWeb
|
||||
|
||||
|
||||
class TestZuulClient(BaseTestWeb):
|
||||
config_file = 'zuul-admin-web.conf'
|
||||
|
||||
def test_is_installed(self):
|
||||
"""Test that the CLI is installed"""
|
||||
test_version = subprocess.check_output(
|
||||
['zuul-client', '--version'],
|
||||
stderr=subprocess.STDOUT)
|
||||
self.assertTrue(b'Zuul-client version:' in test_version)
|
||||
|
||||
def test_autohold(self):
|
||||
"""Test that autohold can be set with the Web client"""
|
||||
authz = {'iss': 'zuul_operator',
|
||||
'aud': 'zuul.example.com',
|
||||
'sub': 'testuser',
|
||||
'zuul': {
|
||||
'admin': ['tenant-one', ]
|
||||
},
|
||||
'exp': time.time() + 3600}
|
||||
token = jwt.encode(authz, key='NoDanaOnlyZuul',
|
||||
algorithm='HS256').decode('utf-8')
|
||||
p = subprocess.Popen(
|
||||
['zuul-client',
|
||||
'--zuul-url', self.base_url, '--auth-token', token, '-v',
|
||||
'autohold', '--reason', 'some reason',
|
||||
'--tenant', 'tenant-one', '--project', 'org/project',
|
||||
'--job', 'project-test2', '--count', '1'],
|
||||
stdout=subprocess.PIPE)
|
||||
output = p.communicate()
|
||||
self.assertEqual(p.returncode, 0, output)
|
||||
# Check result in rpc client
|
||||
client = zuul.rpcclient.RPCClient('127.0.0.1',
|
||||
self.gearman_server.port)
|
||||
self.addCleanup(client.shutdown)
|
||||
autohold_requests = client.autohold_list()
|
||||
self.assertNotEqual([], autohold_requests)
|
||||
self.assertEqual(1, len(autohold_requests))
|
||||
request = autohold_requests[0]
|
||||
self.assertEqual('tenant-one', request['tenant'])
|
||||
self.assertIn('org/project', request['project'])
|
||||
self.assertEqual('project-test2', request['job'])
|
||||
self.assertEqual(".*", request['ref_filter'])
|
||||
self.assertEqual("some reason", request['reason'])
|
||||
self.assertEqual(1, request['max_count'])
|
||||
|
||||
def test_enqueue(self):
|
||||
"""Test that the Web client can enqueue a change"""
|
||||
self.executor_server.hold_jobs_in_build = True
|
||||
A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
|
||||
A.addApproval('Code-Review', 2)
|
||||
A.addApproval('Approved', 1)
|
||||
|
||||
authz = {'iss': 'zuul_operator',
|
||||
'aud': 'zuul.example.com',
|
||||
'sub': 'testuser',
|
||||
'zuul': {
|
||||
'admin': ['tenant-one', ]
|
||||
},
|
||||
'exp': time.time() + 3600}
|
||||
token = jwt.encode(authz, key='NoDanaOnlyZuul',
|
||||
algorithm='HS256').decode('utf-8')
|
||||
p = subprocess.Popen(
|
||||
['zuul-client',
|
||||
'--zuul-url', self.base_url, '--auth-token', token, '-v',
|
||||
'enqueue', '--tenant', 'tenant-one',
|
||||
'--project', 'org/project',
|
||||
'--pipeline', 'gate', '--change', '1,1'],
|
||||
stdout=subprocess.PIPE)
|
||||
output = p.communicate()
|
||||
self.assertEqual(p.returncode, 0, output)
|
||||
self.waitUntilSettled()
|
||||
# Check the build history for our enqueued build
|
||||
self.executor_server.hold_jobs_in_build = False
|
||||
self.executor_server.release()
|
||||
self.waitUntilSettled()
|
||||
# project-merge, project-test1, project-test2 in SUCCESS
|
||||
self.assertEqual(self.countJobResults(self.history, 'SUCCESS'), 3)
|
||||
|
||||
def test_enqueue_ref(self):
|
||||
"""Test that the Web client can enqueue a ref"""
|
||||
self.executor_server.hold_jobs_in_build = True
|
||||
p = "review.example.com/org/project"
|
||||
upstream = self.getUpstreamRepos([p])
|
||||
A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
|
||||
A.setMerged()
|
||||
A_commit = str(upstream[p].commit('master'))
|
||||
self.log.debug("A commit: %s" % A_commit)
|
||||
|
||||
authz = {'iss': 'zuul_operator',
|
||||
'aud': 'zuul.example.com',
|
||||
'sub': 'testuser',
|
||||
'zuul': {
|
||||
'admin': ['tenant-one', ]
|
||||
},
|
||||
'exp': time.time() + 3600}
|
||||
token = jwt.encode(authz, key='NoDanaOnlyZuul',
|
||||
algorithm='HS256').decode('utf-8')
|
||||
p = subprocess.Popen(
|
||||
['zuul-client',
|
||||
'--zuul-url', self.base_url, '--auth-token', token, '-v',
|
||||
'enqueue-ref', '--tenant', 'tenant-one',
|
||||
'--project', 'org/project',
|
||||
'--pipeline', 'post', '--ref', 'master',
|
||||
'--oldrev', '90f173846e3af9154517b88543ffbd1691f31366',
|
||||
'--newrev', A_commit],
|
||||
stdout=subprocess.PIPE)
|
||||
output = p.communicate()
|
||||
self.assertEqual(p.returncode, 0, output)
|
||||
self.waitUntilSettled()
|
||||
# Check the build history for our enqueued build
|
||||
self.executor_server.hold_jobs_in_build = False
|
||||
self.executor_server.release()
|
||||
self.waitUntilSettled()
|
||||
self.assertEqual(self.countJobResults(self.history, 'SUCCESS'), 1)
|
||||
|
||||
def test_dequeue(self):
|
||||
"""Test that the Web client can dequeue a change"""
|
||||
self.executor_server.hold_jobs_in_build = True
|
||||
start_builds = len(self.builds)
|
||||
self.create_branch('org/project', 'stable')
|
||||
self.executor_server.hold_jobs_in_build = True
|
||||
self.commitConfigUpdate('common-config', 'layouts/timer.yaml')
|
||||
self.scheds.execute(lambda app: app.sched.reconfigure(app.config))
|
||||
self.waitUntilSettled()
|
||||
|
||||
for _ in iterate_timeout(30, 'Wait for a build on hold'):
|
||||
if len(self.builds) > start_builds:
|
||||
break
|
||||
self.waitUntilSettled()
|
||||
|
||||
authz = {'iss': 'zuul_operator',
|
||||
'aud': 'zuul.example.com',
|
||||
'sub': 'testuser',
|
||||
'zuul': {
|
||||
'admin': ['tenant-one', ]
|
||||
},
|
||||
'exp': time.time() + 3600}
|
||||
token = jwt.encode(authz, key='NoDanaOnlyZuul',
|
||||
algorithm='HS256').decode('utf-8')
|
||||
p = subprocess.Popen(
|
||||
['zuul-client',
|
||||
'--zuul-url', self.base_url, '--auth-token', token, '-v',
|
||||
'dequeue', '--tenant', 'tenant-one', '--project', 'org/project',
|
||||
'--pipeline', 'periodic', '--ref', 'refs/heads/stable'],
|
||||
stdout=subprocess.PIPE)
|
||||
output = p.communicate()
|
||||
self.assertEqual(p.returncode, 0, output)
|
||||
self.waitUntilSettled()
|
||||
|
||||
self.commitConfigUpdate('common-config',
|
||||
'layouts/no-timer.yaml')
|
||||
self.scheds.execute(lambda app: app.sched.reconfigure(app.config))
|
||||
self.waitUntilSettled()
|
||||
self.executor_server.hold_jobs_in_build = False
|
||||
self.executor_server.release()
|
||||
self.waitUntilSettled()
|
||||
self.assertEqual(self.countJobResults(self.history, 'ABORTED'), 1)
|
||||
|
||||
def test_promote(self):
|
||||
"Test that the Web client can promote a change"
|
||||
self.executor_server.hold_jobs_in_build = True
|
||||
A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
|
||||
B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
|
||||
C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
|
||||
A.addApproval('Code-Review', 2)
|
||||
B.addApproval('Code-Review', 2)
|
||||
C.addApproval('Code-Review', 2)
|
||||
|
||||
self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
|
||||
self.fake_gerrit.addEvent(B.addApproval('Approved', 1))
|
||||
self.fake_gerrit.addEvent(C.addApproval('Approved', 1))
|
||||
|
||||
self.waitUntilSettled()
|
||||
|
||||
tenant = self.scheds.first.sched.abide.tenants.get('tenant-one')
|
||||
items = tenant.layout.pipelines['gate'].getAllItems()
|
||||
enqueue_times = {}
|
||||
for item in items:
|
||||
enqueue_times[str(item.change)] = item.enqueue_time
|
||||
|
||||
# Promote B and C using the cli
|
||||
authz = {'iss': 'zuul_operator',
|
||||
'aud': 'zuul.example.com',
|
||||
'sub': 'testuser',
|
||||
'zuul': {
|
||||
'admin': ['tenant-one', ]
|
||||
},
|
||||
'exp': time.time() + 3600}
|
||||
token = jwt.encode(authz, key='NoDanaOnlyZuul',
|
||||
algorithm='HS256').decode('utf-8')
|
||||
p = subprocess.Popen(
|
||||
['zuul-client',
|
||||
'--zuul-url', self.base_url, '--auth-token', token, '-v',
|
||||
'promote', '--tenant', 'tenant-one',
|
||||
'--pipeline', 'gate', '--changes', '2,1', '3,1'],
|
||||
stdout=subprocess.PIPE)
|
||||
output = p.communicate()
|
||||
self.assertEqual(p.returncode, 0, output)
|
||||
self.waitUntilSettled()
|
||||
|
||||
# ensure that enqueue times are durable
|
||||
items = tenant.layout.pipelines['gate'].getAllItems()
|
||||
for item in items:
|
||||
self.assertEqual(
|
||||
enqueue_times[str(item.change)], item.enqueue_time)
|
||||
|
||||
self.waitUntilSettled()
|
||||
self.executor_server.release('.*-merge')
|
||||
self.waitUntilSettled()
|
||||
self.executor_server.release('.*-merge')
|
||||
self.waitUntilSettled()
|
||||
self.executor_server.release('.*-merge')
|
||||
self.waitUntilSettled()
|
||||
|
||||
self.assertEqual(len(self.builds), 6)
|
||||
self.assertEqual(self.builds[0].name, 'project-test1')
|
||||
self.assertEqual(self.builds[1].name, 'project-test2')
|
||||
self.assertEqual(self.builds[2].name, 'project-test1')
|
||||
self.assertEqual(self.builds[3].name, 'project-test2')
|
||||
self.assertEqual(self.builds[4].name, 'project-test1')
|
||||
self.assertEqual(self.builds[5].name, 'project-test2')
|
||||
|
||||
self.assertTrue(self.builds[0].hasChanges(B))
|
||||
self.assertFalse(self.builds[0].hasChanges(A))
|
||||
self.assertFalse(self.builds[0].hasChanges(C))
|
||||
|
||||
self.assertTrue(self.builds[2].hasChanges(B))
|
||||
self.assertTrue(self.builds[2].hasChanges(C))
|
||||
self.assertFalse(self.builds[2].hasChanges(A))
|
||||
|
||||
self.assertTrue(self.builds[4].hasChanges(B))
|
||||
self.assertTrue(self.builds[4].hasChanges(C))
|
||||
self.assertTrue(self.builds[4].hasChanges(A))
|
||||
|
||||
self.executor_server.release()
|
||||
self.waitUntilSettled()
|
||||
|
||||
self.assertEqual(A.data['status'], 'MERGED')
|
||||
self.assertEqual(A.reported, 2)
|
||||
self.assertEqual(B.data['status'], 'MERGED')
|
||||
self.assertEqual(B.reported, 2)
|
||||
self.assertEqual(C.data['status'], 'MERGED')
|
||||
self.assertEqual(C.reported, 2)
|
8
tox.ini
8
tox.ini
@ -87,6 +87,14 @@ commands = {posargs}
|
||||
commands =
|
||||
stestr run --concurrency=1 --test-path ./tests/nodepool {posargs}
|
||||
|
||||
[testenv:zuul_client]
|
||||
commands =
|
||||
stestr run --concurrency=1 --test-path ./tests/zuul_client {posargs}
|
||||
deps =
|
||||
zuul-client
|
||||
-r{toxinidir}/test-requirements.txt
|
||||
-r{toxinidir}/requirements.txt
|
||||
|
||||
[testenv:remote]
|
||||
passenv =
|
||||
DOCKER_*
|
||||
|
Loading…
x
Reference in New Issue
Block a user