17
17
from .ws_client import get_websocket_url
18
18
from .ws_client import websocket_proxycare
19
19
from kubernetes .client .configuration import Configuration
20
+ import os
21
+ import socket
22
+ import threading
23
+ import pytest
24
+ from kubernetes import stream , client , config
20
25
21
26
try :
22
27
import urllib3
23
28
urllib3 .disable_warnings ()
24
29
except ImportError :
25
30
pass
31
+ @pytest .fixture (autouse = True )
32
+ def dummy_kubeconfig (tmp_path , monkeypatch ):
33
+ # Creating a kubeconfig
34
+ content = """
35
+ apiVersion: v1
36
+ kind: Config
37
+ clusters:
38
+ - name: default
39
+ cluster:
40
+ server: http://127.0.0.1:8888
41
+ contexts:
42
+ - name: default
43
+ context:
44
+ cluster: default
45
+ user: default
46
+ users:
47
+ - name: default
48
+ user: {}
49
+ current-context: default
50
+ """
51
+ cfg_file = tmp_path / "kubeconfig"
52
+ cfg_file .write_text (content )
53
+ monkeypatch .setenv ("KUBECONFIG" , str (cfg_file ))
26
54
27
- def dictval (dict , key , default = None ):
28
- try :
29
- val = dict [key ]
30
- except KeyError :
31
- val = default
32
- return val
55
+
56
+ def dictval (dict_obj , key , default = None ):
57
+
58
+ return dict_obj .get (key , default )
59
+
60
+ class DummyProxy (threading .Thread ):
61
+ """
62
+ A minimal HTTP proxy that flags any CONNECT request and returns 200 OK.
63
+ Listens on 127.0.0.1:8888 by default.
64
+ """
65
+ def __init__ (self , host = '127.0.0.1' , port = 8888 ):
66
+ super ().__init__ (daemon = True )
67
+ self .host = host
68
+ self .port = port
69
+ self .received_connect = False
70
+ self ._server_sock = socket .socket (socket .AF_INET , socket .SOCK_STREAM )
71
+ self ._server_sock .setsockopt (socket .SOL_SOCKET , socket .SO_REUSEADDR , 1 )
72
+ self ._server_sock .bind ((self .host , self .port ))
73
+ self ._server_sock .listen (1 )
74
+
75
+ def run (self ):
76
+ conn , _ = self ._server_sock .accept ()
77
+ try :
78
+ data = conn .recv (1024 ).decode ('utf-8' , errors = 'ignore' )
79
+ if data .startswith ('CONNECT ' ):
80
+ self .received_connect = True
81
+ conn .sendall (b"HTTP/1.1 200 Connection established\r \n \r \n " )
82
+ finally :
83
+ conn .close ()
33
84
34
85
class WSClientTest (unittest .TestCase ):
35
86
@@ -56,21 +107,68 @@ def test_websocket_proxycare(self):
56
107
( 'http://proxy.example.com:8080/' , 'user:pass' , '.example.com' , 'proxy.example.com' , 8080 , ('user' ,'pass' ), ['.example.com' ]),
57
108
( 'http://proxy.example.com:8080/' , 'user:pass' , 'localhost,.local,.example.com' , 'proxy.example.com' , 8080 , ('user' ,'pass' ), ['localhost' ,'.local' ,'.example.com' ]),
58
109
]:
59
- # setup input
60
- config = Configuration ()
61
- if proxy is not None :
62
- setattr ( config , ' proxy' , proxy )
63
- if idpass is not None :
64
- setattr ( config , ' proxy_headers' , urllib3 .util .make_headers (proxy_basic_auth = idpass ) )
110
+ # input setup
111
+ cfg = Configuration ()
112
+ if proxy :
113
+ cfg . proxy = proxy
114
+ if idpass :
115
+ cfg . proxy_headers = urllib3 .util .make_headers (proxy_basic_auth = idpass )
65
116
if no_proxy is not None :
66
- setattr (config , 'no_proxy' , no_proxy )
67
- # setup done
68
- # test starts
69
- connect_opt = websocket_proxycare ( {}, config , None , None )
70
- self .assertEqual ( dictval (connect_opt ,'http_proxy_host' ), expect_host )
71
- self .assertEqual ( dictval (connect_opt ,'http_proxy_port' ), expect_port )
72
- self .assertEqual ( dictval (connect_opt ,'http_proxy_auth' ), expect_auth )
73
- self .assertEqual ( dictval (connect_opt ,'http_no_proxy' ), expect_noproxy )
117
+ cfg .no_proxy = no_proxy
118
+
119
+
120
+ connect_opts = websocket_proxycare ({}, cfg , None , None )
121
+ assert dictval (connect_opts , 'http_proxy_host' ) == expect_host
122
+ assert dictval (connect_opts , 'http_proxy_port' ) == expect_port
123
+ assert dictval (connect_opts , 'http_proxy_auth' ) == expect_auth
124
+ assert dictval (connect_opts , 'http_no_proxy' ) == expect_noproxy
125
+
126
+ @pytest .fixture (scope = "module" )
127
+ def dummy_proxy ():
128
+ #Dummy Proxy
129
+ proxy = DummyProxy (port = 8888 )
130
+ proxy .start ()
131
+ yield proxy
132
+
133
+ @pytest .fixture (autouse = True )
134
+ def clear_proxy_env (monkeypatch ):
135
+ for var in ("HTTP_PROXY" , "http_proxy" , "HTTPS_PROXY" , "https_proxy" , "NO_PROXY" , "no_proxy" ):
136
+ monkeypatch .delenv (var , raising = False )
137
+
138
+ def apply_proxy_to_conf ():
139
+ #apply HTTPS_PROXY env var and set it as global.
140
+ cfg = client .Configuration .get_default_copy ()
141
+ cfg .proxy = os .getenv ("HTTPS_PROXY" )
142
+ cfg .no_proxy = os .getenv ("NO_PROXY" , "" )
143
+ client .Configuration .set_default (cfg )
144
+
145
+ def test_rest_call_ignores_env (dummy_proxy , monkeypatch ):
146
+ # HTTPS_PROXY to dummy proxy
147
+ monkeypatch .setenv ("HTTPS_PROXY" , "http://127.0.0.1:8888" )
148
+ # Avoid real HTTP request
149
+ monkeypatch .setattr (client .CoreV1Api , "list_namespace" , lambda self , * _args , ** _kwargs : None )
150
+ # Load config using kubeconfig
151
+ config .load_kube_config (config_file = os .environ ["KUBECONFIG" ])
152
+ apply_proxy_to_conf ()
153
+ # HTTPS_PROXY to dummy proxy
154
+ monkeypatch .setenv ("HTTPS_PROXY" , "http://127.0.0.1:8888" )
155
+ config .load_kube_config (config_file = os .environ ["KUBECONFIG" ])
156
+ apply_proxy_to_conf ()
157
+ v1 = client .CoreV1Api ()
158
+ v1 .list_namespace (_preload_content = False )
159
+ assert not dummy_proxy .received_connect , "REST path should ignore HTTPS_PROXY"
160
+
161
+ def test_websocket_call_honors_env (dummy_proxy , monkeypatch ):
162
+ # set HTTPS_PROXY again
163
+ monkeypatch .setenv ("HTTPS_PROXY" , "http://127.0.0.1:8888" )
164
+ # Load kubeconfig
165
+ config .load_kube_config (config_file = os .environ ["KUBECONFIG" ])
166
+ apply_proxy_to_conf ()
167
+ opts = websocket_proxycare ({}, client .Configuration .get_default_copy (), None , None )
168
+ assert opts .get ('http_proxy_host' ) == '127.0.0.1'
169
+ assert opts .get ('http_proxy_port' ) == 8888
170
+ # Optionally verify no_proxy parsing
171
+ assert opts .get ('http_no_proxy' ) is None
74
172
75
173
if __name__ == '__main__' :
76
174
unittest .main ()
0 commit comments