summaryrefslogtreecommitdiff
path: root/tests/unit/test_web.py
diff options
context:
space:
mode:
Diffstat (limited to 'tests/unit/test_web.py')
-rw-r--r--tests/unit/test_web.py129
1 files changed, 123 insertions, 6 deletions
diff --git a/tests/unit/test_web.py b/tests/unit/test_web.py
index 4b696534b..5d38c5b19 100644
--- a/tests/unit/test_web.py
+++ b/tests/unit/test_web.py
@@ -28,6 +28,7 @@ from unittest import skip
import requests
from zuul.lib.statsd import normalize_statsd_name
+from zuul.zk.locks import tenant_write_lock
import zuul.web
from tests.base import ZuulTestCase, AnsibleZuulTestCase
@@ -259,6 +260,8 @@ class TestWeb(BaseTestWeb):
def test_web_tenants(self):
"Test that we can retrieve JSON status info"
+ # Disable tenant list caching
+ self.web.web.api.cache_expiry = 0
self.add_base_changes()
self.executor_server.hold_jobs_in_build = True
A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
@@ -315,6 +318,7 @@ class TestWeb(BaseTestWeb):
'baseurl': 'https://review.example.com',
'canonical_hostname': 'review.example.com',
'server': 'review.example.com',
+ 'ssh_server': 'review.example.com',
'port': 29418,
}
self.assertEqual([connection], data)
@@ -371,6 +375,7 @@ class TestWeb(BaseTestWeb):
'ansible_version': None,
'attempts': 4,
'branches': [],
+ 'deduplicate': 'auto',
'dependencies': [],
'description': None,
'files': [],
@@ -421,6 +426,7 @@ class TestWeb(BaseTestWeb):
'ansible_version': None,
'attempts': 3,
'branches': ['stable'],
+ 'deduplicate': 'auto',
'dependencies': [],
'description': None,
'files': [],
@@ -475,6 +481,7 @@ class TestWeb(BaseTestWeb):
'ansible_version': None,
'attempts': 3,
'branches': [],
+ 'deduplicate': 'auto',
'dependencies': [],
'description': None,
'files': [],
@@ -598,6 +605,7 @@ class TestWeb(BaseTestWeb):
'ansible_version': None,
'attempts': 3,
'branches': [],
+ 'deduplicate': 'auto',
'dependencies': [],
'description': None,
'files': [],
@@ -636,6 +644,7 @@ class TestWeb(BaseTestWeb):
'ansible_version': None,
'attempts': 3,
'branches': [],
+ 'deduplicate': 'auto',
'dependencies': [{'name': 'project-merge',
'soft': False}],
'description': None,
@@ -675,6 +684,7 @@ class TestWeb(BaseTestWeb):
'ansible_version': None,
'attempts': 3,
'branches': [],
+ 'deduplicate': 'auto',
'dependencies': [{'name': 'project-merge',
'soft': False}],
'description': None,
@@ -714,6 +724,7 @@ class TestWeb(BaseTestWeb):
'ansible_version': None,
'attempts': 3,
'branches': [],
+ 'deduplicate': 'auto',
'dependencies': [{'name': 'project-merge',
'soft': False}],
'description': None,
@@ -778,6 +789,7 @@ class TestWeb(BaseTestWeb):
'ansible_version': None,
'attempts': 3,
'branches': [],
+ 'deduplicate': 'auto',
'dependencies': [],
'description': None,
'files': [],
@@ -929,6 +941,11 @@ class TestWeb(BaseTestWeb):
self.assertEqual("reason text", ah_request['reason'])
self.assertEqual([], ah_request['nodes'])
+ # Unknown tenants return 404
+ resp = self.get_url(
+ "api/tenant/tenant-fifty/autohold")
+ self.assertEqual(404, resp.status_code, resp.text)
+
def test_admin_routes_404_by_default(self):
resp = self.post_url(
"api/tenant/tenant-one/project/org/project/autohold",
@@ -1227,6 +1244,94 @@ class TestWebStatusDisplayBranch(BaseTestWeb):
class TestWebMultiTenant(BaseTestWeb):
tenant_config_file = 'config/multi-tenant/main.yaml'
+ def test_tenant_reconfigure_command(self):
+ # The 'zuul-scheduler tenant-reconfigure' and full-reconfigure
+ # are used to correct problems, and as such they clear the
+ # branch cache. Until the reconfiguration is complete,
+ # zuul-web will be unable to load configuration for any tenant
+ # which has projects that have been cleared from the branch
+ # cache. This test verifies that we retry that operation
+ # after encountering missing branch errors.
+ sched = self.scheds.first.sched
+ web = self.web.web
+ # Don't perform any automatic config updates on zuul web so
+ # that we can control the sequencing.
+ self.web.web._system_config_running = False
+ self.web.web.system_config_cache_wake_event.set()
+ self.web.web.system_config_thread.join()
+
+ first_state = sched.tenant_layout_state.get('tenant-one')
+ self.assertEqual(first_state,
+ web.local_layout_state.get('tenant-one'))
+
+ data = self.get_url('api/tenant/tenant-one/jobs').json()
+ self.assertEqual(len(data), 4)
+
+ # Reconfigure tenant-one so that the layout state will be
+ # different and we can start a layout update in zuul-web
+ # later.
+ self.log.debug("Reconfigure tenant-one")
+ self.scheds.first.tenantReconfigure(['tenant-one'])
+ self.waitUntilSettled()
+ self.log.debug("Done reconfigure tenant-one")
+
+ second_state = sched.tenant_layout_state.get('tenant-one')
+ self.assertEqual(second_state,
+ sched.local_layout_state.get('tenant-one'))
+ self.assertEqual(first_state,
+ web.local_layout_state.get('tenant-one'))
+
+ self.log.debug("Grab write lock for tenant-two")
+ with tenant_write_lock(self.zk_client, 'tenant-two') as lock:
+ # Start a reconfiguration of tenant-two; allow it to
+ # proceed past the point that the branch cache is cleared
+ # and is waiting on the lock we hold.
+ self.scheds.first.tenantReconfigure(
+ ['tenant-two'], command_socket=True)
+ for _ in iterate_timeout(30, "reconfiguration to start"):
+ if 'RECONFIG' in lock.contenders():
+ break
+ # Now that the branch cache is cleared as part of the
+ # tenant-two reconfiguration, allow zuul-web to
+ # reconfigure tenant-one. This should produce an error
+ # because of the missing branch cache.
+ self.log.debug("Web update layout 1")
+ self.web.web.updateSystemConfig()
+ self.assertFalse(self.web.web.updateLayout())
+ self.log.debug("Web update layout done")
+
+ self.assertEqual(second_state,
+ sched.local_layout_state.get('tenant-one'))
+ self.assertEqual(first_state,
+ web.local_layout_state.get('tenant-one'))
+
+ # Make sure we can still access tenant-one's config via
+ # zuul-web
+ data = self.get_url('api/tenant/tenant-one/jobs').json()
+ self.assertEqual(len(data), 4)
+ self.log.debug("Release write lock for tenant-two")
+ for _ in iterate_timeout(30, "reconfiguration to finish"):
+ if 'RECONFIG' not in lock.contenders():
+ break
+
+ self.log.debug("Web update layout 2")
+ self.web.web.updateSystemConfig()
+ self.web.web.updateLayout()
+ self.log.debug("Web update layout done")
+
+ # Depending on tenant order, we may need to run one more time
+ self.log.debug("Web update layout 3")
+ self.web.web.updateSystemConfig()
+ self.assertTrue(self.web.web.updateLayout())
+ self.log.debug("Web update layout done")
+
+ self.assertEqual(second_state,
+ sched.local_layout_state.get('tenant-one'))
+ self.assertEqual(second_state,
+ web.local_layout_state.get('tenant-one'))
+ data = self.get_url('api/tenant/tenant-one/jobs').json()
+ self.assertEqual(len(data), 4)
+
def test_web_labels_allowed_list(self):
labels = ["tenant-one-label", "fake", "tenant-two-label"]
self.fake_nodepool.registerLauncher(labels, "FakeLauncher2")
@@ -1241,6 +1346,8 @@ class TestWebMultiTenant(BaseTestWeb):
def test_tenant_add_remove(self):
"Test that tenants are correctly added/removed to/from the layout"
+ # Disable tenant list caching
+ self.web.web.api.cache_expiry = 0
resp = self.get_url("api/tenants")
data = resp.json()
self.assertEqual(sorted(d["name"] for d in data),
@@ -1278,6 +1385,14 @@ class TestEmptyConfig(BaseTestWeb):
'config/empty-config/git/common-config/new-zuul.yaml')
self.scheds.execute(lambda app: app.sched.reconfigure(app.config))
self.waitUntilSettled()
+
+ layout_scheduler = self.scheds.first.sched.local_layout_state.get(
+ 'tenant-one')
+ for _ in iterate_timeout(10, "local layout of zuul-web to be updated"):
+ layout_web = self.web.web.local_layout_state.get('tenant-one')
+ if layout_web == layout_scheduler:
+ break
+
resp = self.get_url("api/tenant/tenant-one/jobs").json()
self.assertEqual(len(resp), 3)
@@ -2852,7 +2967,7 @@ class TestHeldAttributeInBuildInfo(BaseTestWeb):
class TestWebMulti(BaseTestWeb):
- config_file = 'zuul-gerrit-github.conf'
+ config_file = 'zuul-gerrit-ssh.conf'
def test_web_connections_list_multi(self):
data = self.get_url('api/connections').json()
@@ -2864,6 +2979,7 @@ class TestWebMulti(BaseTestWeb):
'baseurl': url,
'canonical_hostname': 'review.example.com',
'server': 'review.example.com',
+ 'ssh_server': 'ssh-review.example.com',
'port': 29418,
}
github_connection = {
@@ -2872,6 +2988,7 @@ class TestWebMulti(BaseTestWeb):
'driver': 'github',
'name': 'github',
'server': 'github.com',
+ 'repo_cache': None,
}
self.assertEqual([gerrit_connection, github_connection], data)
@@ -2892,7 +3009,7 @@ class TestCLIViaWebApi(BaseTestWeb):
token = jwt.encode(authz, key='NoDanaOnlyZuul',
algorithm='HS256')
p = subprocess.Popen(
- [os.path.join(sys.prefix, 'bin/zuul'),
+ [os.path.join(sys.prefix, 'bin/zuul-admin'),
'--zuul-url', self.base_url, '--auth-token', token,
'autohold', '--reason', 'some reason',
'--tenant', 'tenant-one', '--project', 'org/project',
@@ -2931,7 +3048,7 @@ class TestCLIViaWebApi(BaseTestWeb):
token = jwt.encode(authz, key='NoDanaOnlyZuul',
algorithm='HS256')
p = subprocess.Popen(
- [os.path.join(sys.prefix, 'bin/zuul'),
+ [os.path.join(sys.prefix, 'bin/zuul-admin'),
'--zuul-url', self.base_url, '--auth-token', token,
'enqueue', '--tenant', 'tenant-one',
'--project', 'org/project',
@@ -2960,7 +3077,7 @@ class TestCLIViaWebApi(BaseTestWeb):
token = jwt.encode(authz, key='NoDanaOnlyZuul',
algorithm='HS256')
p = subprocess.Popen(
- [os.path.join(sys.prefix, 'bin/zuul'),
+ [os.path.join(sys.prefix, 'bin/zuul-admin'),
'--zuul-url', self.base_url, '--auth-token', token,
'enqueue-ref', '--tenant', 'tenant-one',
'--project', 'org/project',
@@ -2999,7 +3116,7 @@ class TestCLIViaWebApi(BaseTestWeb):
token = jwt.encode(authz, key='NoDanaOnlyZuul',
algorithm='HS256')
p = subprocess.Popen(
- [os.path.join(sys.prefix, 'bin/zuul'),
+ [os.path.join(sys.prefix, 'bin/zuul-admin'),
'--zuul-url', self.base_url, '--auth-token', token,
'dequeue', '--tenant', 'tenant-one', '--project', 'org/project',
'--pipeline', 'periodic', '--ref', 'refs/heads/stable'],
@@ -3050,7 +3167,7 @@ class TestCLIViaWebApi(BaseTestWeb):
token = jwt.encode(authz, key='NoDanaOnlyZuul',
algorithm='HS256')
p = subprocess.Popen(
- [os.path.join(sys.prefix, 'bin/zuul'),
+ [os.path.join(sys.prefix, 'bin/zuul-admin'),
'--zuul-url', self.base_url, '--auth-token', token,
'promote', '--tenant', 'tenant-one',
'--pipeline', 'gate', '--changes', '2,1', '3,1'],