diff options
Diffstat (limited to 'tests/unit/test_web.py')
-rw-r--r-- | tests/unit/test_web.py | 129 |
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'], |