55import hashlib
66from pathlib import Path
77
8+ import aiohttp
89import pyhelm3
910import pytest
11+ from aiohttp_retry import RetryClient
12+ from lightkube import AsyncClient
13+ from lightkube .resources .core_v1 import Pod
1014
1115from .fixtures import ESSData , User
1216from .lib .helpers import deploy_with_values_patch , get_deployment_marker
1317from .lib .synapse import assert_downloaded_content , download_media , upload_media
14- from .lib .utils import KubeCtl , aiohttp_client , aiohttp_get_json , aiohttp_post_json , value_file_has
18+ from .lib .utils import KubeCtl , aiohttp_client , aiohttp_get_json , aiohttp_post_json , retry_options , value_file_has
1519
1620
1721@pytest .mark .skipif (value_file_has ("synapse.enabled" , False ), reason = "Synapse not deployed" )
@@ -35,7 +39,9 @@ async def test_synapse_can_access_client_api(
3539@pytest .mark .skipif (value_file_has ("synapse.enabled" , False ), reason = "Synapse not deployed" )
3640@pytest .mark .parametrize ("users" , [(User (name = "sliding-sync-user" ),)], indirect = True )
3741@pytest .mark .asyncio_cooperative
38- async def test_simplified_sliding_sync_syncs (ssl_context , users , generated_data : ESSData ):
42+ async def test_simplified_sliding_sync_syncs (ingress_ready , ssl_context , users , generated_data : ESSData ):
43+ await ingress_ready ("synapse" )
44+
3945 access_token = users [0 ].access_token
4046
4147 sync_result = await aiohttp_post_json (
@@ -48,6 +54,79 @@ async def test_simplified_sliding_sync_syncs(ssl_context, users, generated_data:
4854 assert "pos" in sync_result
4955
5056
57+ @pytest .mark .skipif (value_file_has ("synapse.enabled" , False ), reason = "Synapse not deployed" )
58+ @pytest .mark .asyncio_cooperative
59+ async def test_routes_to_synapse_workers_correctly (
60+ ingress_ready , kube_client : AsyncClient , ssl_context , generated_data : ESSData
61+ ):
62+ await ingress_ready ("synapse" )
63+
64+ main_backend = "main/main"
65+ if value_file_has ("synapse.workers.sliding-sync.enabled" , True ):
66+ sliding_sync_backend = "sliding-sync/sliding-sync"
67+ else :
68+ sliding_sync_backend = main_backend
69+
70+ if value_file_has ("synapse.workers.synchrotron.enabled" , True ):
71+ synchrotron_backend = "synchrotron/synchrotron"
72+ else :
73+ synchrotron_backend = main_backend
74+
75+ if value_file_has ("synapse.workers.initial-synchrotron.enabled" , True ):
76+ initial_synchrotron_backend = "initial-synchrotron/initial-sync"
77+ else :
78+ initial_synchrotron_backend = synchrotron_backend
79+
80+ # We don't care about any of these succeeding, only that the requests are made and HAProxy dispatches correctly
81+ # So no auth required and parameters can be made up
82+ paths_to_backends = {
83+ # initial-synchrotron
84+ "/_matrix/client/v3/initialSync" : initial_synchrotron_backend ,
85+ "/_matrix/client/v3/rooms/aroomid/initialSync" : initial_synchrotron_backend ,
86+ "/_matrix/client/v3/sync?full_state=true" : initial_synchrotron_backend ,
87+ "/_matrix/client/v3/sync" : initial_synchrotron_backend ,
88+ "/_matrix/client/v3/events" : initial_synchrotron_backend ,
89+ # synchrotron
90+ "/_matrix/client/v3/sync?since=recently" : synchrotron_backend ,
91+ "/_matrix/client/v3/events?from=recently" : synchrotron_backend ,
92+ # sliding-sync
93+ "/_matrix/client/unstable/org.matrix.simplified_msc3575/sync" : sliding_sync_backend ,
94+ # Would be client-reader but not configured in tests
95+ "/_matrix/client/versions" : main_backend ,
96+ }
97+
98+ for path in paths_to_backends :
99+ host = f"synapse.{ generated_data .server_name } "
100+ url = f"https://127.0.0.1{ path } "
101+ async with (
102+ aiohttp .ClientSession (connector = aiohttp .TCPConnector (ssl = ssl_context )) as session ,
103+ RetryClient (session , retry_options = retry_options , raise_for_status = False ) as client ,
104+ client .get (url , headers = {"Host" : host }, server_hostname = host ) as response ,
105+ ):
106+ # 200 for no auth required (/_matrix/client/versions)
107+ # 401 for most paths that require auth
108+ # 405 for sliding sync that doesn't do GET
109+ assert response .status in [200 , 401 , 405 ], f"{ path } had an unexpected status"
110+
111+ http_log_lines = []
112+ async for haproxy_pod in kube_client .list (
113+ Pod , namespace = generated_data .ess_namespace , labels = {"app.kubernetes.io/name" : "haproxy" }
114+ ):
115+ assert haproxy_pod .metadata
116+ assert haproxy_pod .metadata .name
117+ assert haproxy_pod .metadata .namespace
118+ async for log_line in kube_client .log (haproxy_pod .metadata .name , namespace = haproxy_pod .metadata .namespace ):
119+ if "HTTP/1.1" in log_line :
120+ http_log_lines .append (log_line )
121+
122+ for path , backend in paths_to_backends .items ():
123+ matching_lines = [line for line in http_log_lines if f"GET { path } HTTP/1.1" in line ]
124+
125+ assert len (matching_lines ) > 0 , f"Requests for { path } did not appear in the HAProxy logs"
126+ for matching_line in matching_lines :
127+ assert f"synapse-http-in synapse-{ backend } " in matching_line , f"{ path } was routed unexpectedly"
128+
129+
51130@pytest .mark .skipif (value_file_has ("synapse.enabled" , False ), reason = "Synapse not deployed" )
52131@pytest .mark .parametrize ("users" , [(User (name = "media-upload-unauth" ),)], indirect = True )
53132@pytest .mark .asyncio_cooperative
0 commit comments