11import importlib
22import inspect
3+ import os
34import pkgutil
45import unittest
6+ import urllib .request
7+ from typing import Optional
8+
9+ from testcontainers .core .container import DockerContainer
10+ from testcontainers .core .network import Network
11+ from testcontainers .core .wait_strategies import PortWaitStrategy
12+ from testcontainers .core .waiting_utils import wait_container_is_ready
513
614from zitadel_client .auth .no_auth_authenticator import NoAuthAuthenticator
15+ from zitadel_client .transport_options import TransportOptions
716from zitadel_client .zitadel import Zitadel
817
18+ FIXTURES_DIR = os .path .join (os .path .dirname (__file__ ), "fixtures" )
19+
20+
21+ @wait_container_is_ready ()
22+ def _wait_for_wiremock (host : str , port : str ) -> None :
23+ url = f"http://{ host } :{ port } /__admin/mappings"
24+ with urllib .request .urlopen (url , timeout = 5 ) as resp : # noqa: S310
25+ if resp .status != 200 :
26+ raise ConnectionError (f"WireMock not ready: { resp .status } " )
27+
928
1029class ZitadelServicesTest (unittest .TestCase ):
11- """
12- Test to verify that all API service classes defined in the "zitadel_client.api" namespace
13- are registered as attributes in the Zitadel class.
14- """
1530
1631 def test_services_dynamic (self ) -> None :
1732 expected = set ()
@@ -30,3 +45,114 @@ def test_services_dynamic(self) -> None:
3045 and getattr (zitadel , attr ).__class__ .__module__ .startswith ("zitadel_client.api" )
3146 }
3247 self .assertEqual (expected , actual )
48+
49+
50+ class ZitadelTransportTest (unittest .TestCase ):
51+ host : Optional [str ] = None
52+ http_port : Optional [str ] = None
53+ https_port : Optional [str ] = None
54+ proxy_port : Optional [str ] = None
55+ ca_cert_path : Optional [str ] = None
56+ wiremock : DockerContainer = None
57+ proxy : DockerContainer = None
58+ network : Network = None
59+
60+ @classmethod
61+ def setup_class (cls ) -> None :
62+ cls .ca_cert_path = os .path .join (FIXTURES_DIR , "ca.pem" )
63+ keystore_path = os .path .join (FIXTURES_DIR , "keystore.p12" )
64+ squid_conf = os .path .join (FIXTURES_DIR , "squid.conf" )
65+
66+ cls .network = Network ().create ()
67+
68+ cls .wiremock = (
69+ DockerContainer ("wiremock/wiremock:3.12.1" )
70+ .with_network (cls .network )
71+ .with_network_aliases ("wiremock" )
72+ .with_exposed_ports (8080 , 8443 )
73+ .with_volume_mapping (keystore_path , "/home/wiremock/keystore.p12" , mode = "ro" )
74+ .with_volume_mapping (
75+ os .path .join (FIXTURES_DIR , "mappings" ), "/home/wiremock/mappings" , mode = "ro"
76+ )
77+ .with_command (
78+ "--https-port 8443"
79+ " --https-keystore /home/wiremock/keystore.p12"
80+ " --keystore-password password"
81+ " --keystore-type PKCS12"
82+ " --global-response-templating"
83+ )
84+ )
85+ cls .wiremock .start ()
86+
87+ cls .proxy = (
88+ DockerContainer ("ubuntu/squid:6.10-24.10_beta" )
89+ .with_network (cls .network )
90+ .with_exposed_ports (3128 )
91+ .with_volume_mapping (squid_conf , "/etc/squid/squid.conf" , mode = "ro" )
92+ .waiting_for (PortWaitStrategy (3128 ))
93+ )
94+ cls .proxy .start ()
95+
96+ cls .host = cls .wiremock .get_container_host_ip ()
97+ cls .http_port = cls .wiremock .get_exposed_port (8080 )
98+ cls .https_port = cls .wiremock .get_exposed_port (8443 )
99+ cls .proxy_port = cls .proxy .get_exposed_port (3128 )
100+
101+ _wait_for_wiremock (cls .host , cls .http_port )
102+
103+ @classmethod
104+ def teardown_class (cls ) -> None :
105+ if cls .proxy is not None :
106+ cls .proxy .stop ()
107+ if cls .wiremock is not None :
108+ cls .wiremock .stop ()
109+ if cls .network is not None :
110+ cls .network .remove ()
111+
112+ def test_custom_ca_cert (self ) -> None :
113+ zitadel = Zitadel .with_client_credentials (
114+ f"https://{ self .host } :{ self .https_port } " ,
115+ "dummy-client" ,
116+ "dummy-secret" ,
117+ transport_options = TransportOptions (ca_cert_path = self .ca_cert_path ),
118+ )
119+ response = zitadel .settings .get_general_settings ({})
120+ self .assertEqual ("https" , response .default_language )
121+
122+ def test_insecure_mode (self ) -> None :
123+ zitadel = Zitadel .with_client_credentials (
124+ f"https://{ self .host } :{ self .https_port } " ,
125+ "dummy-client" ,
126+ "dummy-secret" ,
127+ transport_options = TransportOptions (insecure = True ),
128+ )
129+ response = zitadel .settings .get_general_settings ({})
130+ self .assertEqual ("https" , response .default_language )
131+
132+ def test_default_headers (self ) -> None :
133+ zitadel = Zitadel .with_client_credentials (
134+ f"http://{ self .host } :{ self .http_port } " ,
135+ "dummy-client" ,
136+ "dummy-secret" ,
137+ transport_options = TransportOptions (default_headers = {"X-Custom-Header" : "test-value" }),
138+ )
139+ response = zitadel .settings .get_general_settings ({})
140+ self .assertEqual ("http" , response .default_language )
141+ self .assertEqual ("test-value" , response .default_org_id )
142+
143+ def test_proxy_url (self ) -> None :
144+ zitadel = Zitadel .with_access_token (
145+ "http://wiremock:8080" ,
146+ "test-token" ,
147+ transport_options = TransportOptions (proxy_url = f"http://{ self .host } :{ self .proxy_port } " ),
148+ )
149+ response = zitadel .settings .get_general_settings ({})
150+ self .assertEqual ("http" , response .default_language )
151+
152+ def test_no_ca_cert_fails (self ) -> None :
153+ with self .assertRaises (Exception ): # noqa: B017
154+ Zitadel .with_client_credentials (
155+ f"https://{ self .host } :{ self .https_port } " ,
156+ "dummy-client" ,
157+ "dummy-secret" ,
158+ )
0 commit comments