44import urllib .request
55from typing import Optional
66
7+ import docker
78from testcontainers .core .container import DockerContainer
89from testcontainers .core .waiting_utils import wait_container_is_ready
910
@@ -35,13 +36,20 @@ class TransportOptionsTest(unittest.TestCase):
3536 host : Optional [str ] = None
3637 http_port : Optional [str ] = None
3738 https_port : Optional [str ] = None
39+ proxy_port : Optional [str ] = None
3840 ca_cert_path : Optional [str ] = None
3941 wiremock : DockerContainer = None
42+ proxy_docker = None
43+ docker_network = None
4044
4145 @classmethod
4246 def setup_class (cls ) -> None :
4347 cls .ca_cert_path = os .path .join (FIXTURES_DIR , "ca.pem" )
4448 keystore_path = os .path .join (FIXTURES_DIR , "keystore.p12" )
49+ tinyproxy_conf = os .path .join (FIXTURES_DIR , "tinyproxy.conf" )
50+
51+ docker_client = docker .from_env ()
52+ cls .docker_network = docker_client .networks .create ("zitadel-proxy-test" )
4553
4654 cls .wiremock = (
4755 DockerContainer ("wiremock/wiremock:3.3.1" )
@@ -57,9 +65,24 @@ def setup_class(cls) -> None:
5765 )
5866 cls .wiremock .start ()
5967
68+ # Connect WireMock to network with alias so the proxy can resolve it
69+ wiremock_id = cls .wiremock ._container .id
70+ cls .docker_network .connect (wiremock_id , aliases = ["wiremock" ])
71+
72+ # Create proxy directly on the network so Docker DNS resolves 'wiremock'
73+ cls .proxy_docker = docker_client .containers .run (
74+ "vimagick/tinyproxy" ,
75+ detach = True ,
76+ network = "zitadel-proxy-test" ,
77+ ports = {"8888/tcp" : None },
78+ volumes = {tinyproxy_conf : {"bind" : "/etc/tinyproxy/tinyproxy.conf" , "mode" : "ro" }},
79+ )
80+ cls .proxy_docker .reload ()
81+
6082 cls .host = cls .wiremock .get_container_host_ip ()
6183 cls .http_port = cls .wiremock .get_exposed_port (8080 )
6284 cls .https_port = cls .wiremock .get_exposed_port (8443 )
85+ cls .proxy_port = cls .proxy_docker .ports ["8888/tcp" ][0 ]["HostPort" ]
6386
6487 _wait_for_wiremock (cls .host , cls .http_port )
6588
@@ -141,8 +164,13 @@ def setup_class(cls) -> None:
141164
142165 @classmethod
143166 def teardown_class (cls ) -> None :
167+ if cls .proxy_docker is not None :
168+ cls .proxy_docker .stop ()
169+ cls .proxy_docker .remove ()
144170 if cls .wiremock is not None :
145171 cls .wiremock .stop ()
172+ if cls .docker_network is not None :
173+ cls .docker_network .remove ()
146174
147175 def test_custom_ca_cert (self ) -> None :
148176 zitadel = Zitadel .with_client_credentials (
@@ -193,12 +221,14 @@ def test_default_headers(self) -> None:
193221 self .assertGreaterEqual (result ["count" ], 1 , "Custom header should be present on API call" )
194222
195223 def test_proxy_url (self ) -> None :
224+ # Use Docker-internal hostname — only resolvable through the proxy's network
196225 zitadel = Zitadel .with_access_token (
197- f "http://{ self . host } : { self . http_port } " ,
226+ "http://wiremock:8080 " ,
198227 "test-token" ,
199- transport_options = TransportOptions (proxy_url = f"http://{ self .host } :{ self .http_port } " ),
228+ transport_options = TransportOptions (proxy_url = f"http://{ self .host } :{ self .proxy_port } " ),
200229 )
201230 self .assertIsNotNone (zitadel )
231+ zitadel .settings .get_general_settings ({})
202232
203233 def test_no_ca_cert_fails (self ) -> None :
204234 with self .assertRaises (Exception ): # noqa: B017
0 commit comments