Path: blob/trunk/py/test/unit/selenium/webdriver/remote/remote_connection_tests.py
4012 views
# Licensed to the Software Freedom Conservancy (SFC) under one1# or more contributor license agreements. See the NOTICE file2# distributed with this work for additional information3# regarding copyright ownership. The SFC licenses this file4# to you under the Apache License, Version 2.0 (the5# "License"); you may not use this file except in compliance6# with the License. You may obtain a copy of the License at7#8# http://www.apache.org/licenses/LICENSE-2.09#10# Unless required by applicable law or agreed to in writing,11# software distributed under the License is distributed on an12# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY13# KIND, either express or implied. See the License for the14# specific language governing permissions and limitations15# under the License.1617import base6418import os19from unittest.mock import patch20from urllib import parse2122import pytest23from urllib3 import PoolManager, ProxyManager, make_headers24from urllib3.contrib.socks import SOCKSProxyManager25from urllib3.util import Retry, Timeout2627from selenium import __version__28from selenium.webdriver import Proxy29from selenium.webdriver.common.proxy import ProxyType30from selenium.webdriver.remote.client_config import AuthType31from selenium.webdriver.remote.remote_connection import ClientConfig, RemoteConnection323334@pytest.fixture35def remote_connection():36"""Fixture to create a RemoteConnection instance."""37return RemoteConnection("http://localhost:4444")383940def test_add_command(remote_connection):41"""Test adding a custom command to the connection."""42remote_connection.add_command("CUSTOM_COMMAND", "PUT", "/session/$sessionId/custom")43assert remote_connection.get_command("CUSTOM_COMMAND") == ("PUT", "/session/$sessionId/custom")444546@patch("selenium.webdriver.remote.remote_connection.RemoteConnection._request")47def test_execute_custom_command(mock_request, remote_connection):48"""Test executing a custom command through the connection."""49remote_connection.add_command("CUSTOM_COMMAND", "PUT", "/session/$sessionId/custom")50mock_request.return_value = {"status": 200, "value": "OK"}5152params = {"sessionId": "12345"}53response = remote_connection.execute("CUSTOM_COMMAND", params)5455mock_request.assert_called_once_with("PUT", "http://localhost:4444/session/12345/custom", body="{}")56assert response == {"status": 200, "value": "OK"}575859def test_default_websocket_settings():60config = ClientConfig(remote_server_addr="http://localhost:4444")61assert config.websocket_timeout == 30.062assert config.websocket_interval == 0.1636465def test_get_remote_connection_headers_defaults():66url = "http://remote"67headers = RemoteConnection.get_remote_connection_headers(parse.urlparse(url))68assert "Authorization" not in headers69assert "Connection" not in headers70assert headers.get("Accept") == "application/json"71assert headers.get("Content-Type") == "application/json;charset=UTF-8"72assert headers.get("User-Agent").startswith(f"selenium/{__version__} (python ")73assert headers.get("User-Agent").split(" ")[-1].rstrip(")") in ("win32", "windows", "mac", "linux")747576def test_get_remote_connection_headers_adds_auth_header_if_pass(recwarn):77url = "http://user:pass@remote"78headers = RemoteConnection.get_remote_connection_headers(parse.urlparse(url))79assert headers.get("Authorization") == "Basic dXNlcjpwYXNz"80assert (81recwarn[0].message.args[0]82== "Embedding username and password in URL could be insecure, use ClientConfig instead"83)848586def test_get_remote_connection_headers_adds_keep_alive_if_requested():87url = "http://remote"88headers = RemoteConnection.get_remote_connection_headers(parse.urlparse(url), keep_alive=True)89assert headers.get("Connection") == "keep-alive"909192def test_get_proxy_url_http(mock_proxy_settings):93proxy = "http://http_proxy.com:8080"94remote_connection = RemoteConnection("http://remote", keep_alive=False)95proxy_url = remote_connection.client_config.get_proxy_url()96assert proxy_url == proxy979899def test_get_auth_header_if_client_config_pass_basic_auth():100custom_config = ClientConfig(101remote_server_addr="http://localhost:4444",102keep_alive=True,103username="user",104password="pass",105auth_type=AuthType.BASIC,106)107remote_connection = RemoteConnection(custom_config.remote_server_addr, client_config=custom_config)108headers = remote_connection.client_config.get_auth_header()109assert headers.get("Authorization") == "Basic dXNlcjpwYXNz"110111112def test_get_auth_header_if_client_config_pass_bearer_token():113custom_config = ClientConfig(114remote_server_addr="http://localhost:4444", keep_alive=True, auth_type=AuthType.BEARER, token="dXNlcjpwYXNz"115)116remote_connection = RemoteConnection(custom_config.remote_server_addr, client_config=custom_config)117headers = remote_connection.client_config.get_auth_header()118assert headers.get("Authorization") == "Bearer dXNlcjpwYXNz"119120121def test_get_auth_header_if_client_config_pass_x_api_key():122custom_config = ClientConfig(123remote_server_addr="http://localhost:4444",124keep_alive=True,125auth_type=AuthType.X_API_KEY,126token="abcdefgh123456789",127)128remote_connection = RemoteConnection(custom_config.remote_server_addr, client_config=custom_config)129headers = remote_connection.client_config.get_auth_header()130assert headers.get("X-API-Key") == "abcdefgh123456789"131132133def test_get_proxy_url_https(mock_proxy_settings):134proxy = "http://https_proxy.com:8080"135remote_connection = RemoteConnection("https://remote", keep_alive=False)136proxy_url = remote_connection.client_config.get_proxy_url()137assert proxy_url == proxy138139140def test_get_proxy_url_https_via_client_config():141client_config = ClientConfig(142remote_server_addr="https://localhost:4444",143proxy=Proxy({"proxyType": ProxyType.MANUAL, "sslProxy": "https://admin:admin@http_proxy.com:8080"}),144)145remote_connection = RemoteConnection(client_config=client_config)146conn = remote_connection._get_connection_manager()147assert isinstance(conn, ProxyManager)148conn.proxy_url = "https://http_proxy.com:8080"149conn.connection_pool_kw["proxy_headers"] = make_headers(proxy_basic_auth="admin:admin")150151152def test_get_proxy_url_http_via_client_config():153client_config = ClientConfig(154remote_server_addr="http://localhost:4444",155proxy=Proxy(156{157"proxyType": ProxyType.MANUAL,158"httpProxy": "http://admin:admin@http_proxy.com:8080",159"sslProxy": "https://admin:admin@http_proxy.com:8080",160}161),162)163remote_connection = RemoteConnection(client_config=client_config)164conn = remote_connection._get_connection_manager()165assert isinstance(conn, ProxyManager)166conn.proxy_url = "http://http_proxy.com:8080"167conn.connection_pool_kw["proxy_headers"] = make_headers(proxy_basic_auth="admin:admin")168169170def test_get_proxy_direct_via_client_config():171client_config = ClientConfig(172remote_server_addr="http://localhost:4444", proxy=Proxy({"proxyType": ProxyType.DIRECT})173)174remote_connection = RemoteConnection(client_config=client_config)175conn = remote_connection._get_connection_manager()176assert isinstance(conn, PoolManager)177proxy_url = remote_connection.client_config.get_proxy_url()178assert proxy_url is None179180181def test_get_proxy_system_matches_no_proxy_via_client_config():182with patch.dict(183"os.environ", {"HTTP_PROXY": "http://admin:admin@system_proxy.com:8080", "NO_PROXY": "localhost,127.0.0.1"}184):185client_config = ClientConfig(186remote_server_addr="http://localhost:4444", proxy=Proxy({"proxyType": ProxyType.SYSTEM})187)188remote_connection = RemoteConnection(client_config=client_config)189conn = remote_connection._get_connection_manager()190assert isinstance(conn, PoolManager)191proxy_url = remote_connection.client_config.get_proxy_url()192assert proxy_url is None193194195def test_get_proxy_url_none(mock_proxy_settings_missing):196remote_connection = RemoteConnection("https://remote", keep_alive=False)197proxy_url = remote_connection.client_config.get_proxy_url()198assert proxy_url is None199200201def test_get_proxy_url_http_auth(mock_proxy_auth_settings):202remote_connection = RemoteConnection("http://remote", keep_alive=False)203proxy_url = remote_connection.client_config.get_proxy_url()204raw_proxy_url, basic_auth_string = remote_connection._separate_http_proxy_auth()205assert proxy_url == "http://user:password@http_proxy.com:8080"206assert raw_proxy_url == "http://http_proxy.com:8080"207assert basic_auth_string == "user:password"208209210def test_get_proxy_url_https_auth(mock_proxy_auth_settings):211remote_connection = RemoteConnection("https://remote", keep_alive=False)212proxy_url = remote_connection.client_config.get_proxy_url()213raw_proxy_url, basic_auth_string = remote_connection._separate_http_proxy_auth()214assert proxy_url == "https://user:password@https_proxy.com:8080"215assert raw_proxy_url == "https://https_proxy.com:8080"216assert basic_auth_string == "user:password"217218219def test_get_connection_manager_without_proxy(mock_proxy_settings_missing):220remote_connection = RemoteConnection("http://remote", keep_alive=False)221conn = remote_connection._get_connection_manager()222assert isinstance(conn, PoolManager)223224225def test_get_connection_manager_for_certs_and_timeout():226remote_connection = RemoteConnection("http://remote", keep_alive=False)227remote_connection.set_timeout(10)228assert remote_connection.get_timeout() == 10229conn = remote_connection._get_connection_manager()230assert conn.connection_pool_kw["timeout"] == 10231assert conn.connection_pool_kw["cert_reqs"] == "CERT_REQUIRED"232assert f"certifi{os.path.sep}cacert.pem" in conn.connection_pool_kw["ca_certs"]233234235def test_default_socket_timeout_is_correct():236remote_connection = RemoteConnection("http://remote", keep_alive=True)237conn = remote_connection._get_connection_manager()238assert conn.connection_pool_kw["timeout"] is None239240241def test_get_connection_manager_with_http_proxy(mock_proxy_settings):242remote_connection = RemoteConnection("http://remote", keep_alive=False)243conn = remote_connection._get_connection_manager()244assert isinstance(conn, ProxyManager)245assert conn.proxy.scheme == "http"246assert conn.proxy.host == "http_proxy.com"247assert conn.proxy.port == 8080248249250def test_get_connection_manager_with_https_proxy(mock_proxy_settings):251remote_connection_https = RemoteConnection("https://remote", keep_alive=False)252conn = remote_connection_https._get_connection_manager()253assert isinstance(conn, ProxyManager)254assert conn.proxy.scheme == "http"255assert conn.proxy.host == "https_proxy.com"256assert conn.proxy.port == 8080257258259def test_get_connection_manager_with_auth_http_proxy(mock_proxy_auth_settings):260proxy_auth_header = make_headers(proxy_basic_auth="user:password")261remote_connection = RemoteConnection("http://remote", keep_alive=False)262conn = remote_connection._get_connection_manager()263assert isinstance(conn, ProxyManager)264assert conn.proxy.scheme == "http"265assert conn.proxy.host == "http_proxy.com"266assert conn.proxy.port == 8080267assert conn.proxy_headers == proxy_auth_header268269270def test_get_connection_manager_with_auth_https_proxy(mock_proxy_auth_settings):271proxy_auth_header = make_headers(proxy_basic_auth="user:password")272remote_connection_https = RemoteConnection("https://remote", keep_alive=False)273conn = remote_connection_https._get_connection_manager()274assert isinstance(conn, ProxyManager)275assert conn.proxy.scheme == "https"276assert conn.proxy.host == "https_proxy.com"277assert conn.proxy.port == 8080278assert conn.proxy_headers == proxy_auth_header279280281@pytest.mark.parametrize(282"url",283[284"*",285".localhost",286"localhost:80",287"localhost",288"LOCALHOST",289"LOCALHOST:80",290"http://localhost",291"https://localhost",292"test.localhost",293" localhost",294"127.0.0.1",295"127.0.0.2",296"::1",297],298)299def test_get_connection_manager_when_no_proxy_set(mock_no_proxy_settings, url):300remote_connection = RemoteConnection(url)301conn = remote_connection._get_connection_manager()302assert isinstance(conn, PoolManager)303304305def test_ignore_proxy_env_vars(mock_proxy_settings):306remote_connection = RemoteConnection("http://remote", ignore_proxy=True)307conn = remote_connection._get_connection_manager()308assert isinstance(conn, PoolManager)309310311def test_get_socks_proxy_when_set(mock_socks_proxy_settings):312remote_connection = RemoteConnection("http://remote")313conn = remote_connection._get_connection_manager()314315assert isinstance(conn, SOCKSProxyManager)316317318class MockResponse:319code = 200320headers = []321322def read(self):323return b"{}"324325def close(self):326pass327328def getheader(self, *args, **kwargs):329pass330331332@pytest.fixture333def mock_proxy_settings_missing(monkeypatch):334monkeypatch.delenv("HTTPS_PROXY", raising=False)335monkeypatch.delenv("HTTP_PROXY", raising=False)336monkeypatch.delenv("https_proxy", raising=False)337monkeypatch.delenv("http_proxy", raising=False)338339340@pytest.fixture341def mock_socks_proxy_settings(monkeypatch):342http_proxy = "SOCKS5://http_proxy.com:8080"343https_proxy = "SOCKS5://https_proxy.com:8080"344monkeypatch.setenv("HTTPS_PROXY", https_proxy)345monkeypatch.setenv("HTTP_PROXY", http_proxy)346monkeypatch.setenv("https_proxy", https_proxy)347monkeypatch.setenv("http_proxy", http_proxy)348349350@pytest.fixture351def mock_proxy_settings(monkeypatch):352http_proxy = "http://http_proxy.com:8080"353https_proxy = "http://https_proxy.com:8080"354monkeypatch.setenv("HTTPS_PROXY", https_proxy)355monkeypatch.setenv("HTTP_PROXY", http_proxy)356monkeypatch.setenv("https_proxy", https_proxy)357monkeypatch.setenv("http_proxy", http_proxy)358359360@pytest.fixture361def mock_proxy_auth_settings(monkeypatch):362http_proxy = "http://user:password@http_proxy.com:8080"363https_proxy = "https://user:password@https_proxy.com:8080"364monkeypatch.setenv("HTTPS_PROXY", https_proxy)365monkeypatch.setenv("HTTP_PROXY", http_proxy)366monkeypatch.setenv("https_proxy", https_proxy)367monkeypatch.setenv("http_proxy", http_proxy)368369370@pytest.fixture371def mock_no_proxy_settings(monkeypatch):372http_proxy = "http://http_proxy.com:8080"373https_proxy = "http://https_proxy.com:8080"374monkeypatch.setenv("HTTPS_PROXY", https_proxy)375monkeypatch.setenv("HTTP_PROXY", http_proxy)376monkeypatch.setenv("https_proxy", https_proxy)377monkeypatch.setenv("http_proxy", http_proxy)378monkeypatch.setenv("no_proxy", "65.253.214.253,localhost,127.0.0.1,*zyz.xx,::1")379monkeypatch.setenv("NO_PROXY", "65.253.214.253,localhost,127.0.0.1,*zyz.xx,::1,127.0.0.0/8")380381382@patch("selenium.webdriver.remote.remote_connection.RemoteConnection.get_remote_connection_headers")383def test_override_user_agent_in_headers(mock_get_remote_connection_headers, remote_connection):384RemoteConnection.user_agent = "custom-agent/1.0 (python 3.13)"385386mock_get_remote_connection_headers.return_value = {387"Accept": "application/json",388"Content-Type": "application/json;charset=UTF-8",389"User-Agent": "custom-agent/1.0 (python 3.13)",390}391392headers = RemoteConnection.get_remote_connection_headers(parse.urlparse("http://remote"))393394assert headers.get("User-Agent") == "custom-agent/1.0 (python 3.13)"395assert headers.get("Accept") == "application/json"396assert headers.get("Content-Type") == "application/json;charset=UTF-8"397398399@patch("selenium.webdriver.remote.remote_connection.RemoteConnection.get_remote_connection_headers")400def test_override_user_agent_via_client_config(mock_get_remote_connection_headers):401client_config = ClientConfig(402remote_server_addr="http://localhost:4444",403user_agent="custom-agent/1.0 (python 3.13)",404extra_headers={"Content-Type": "application/xml;charset=UTF-8"},405)406remote_connection = RemoteConnection(client_config=client_config)407408mock_get_remote_connection_headers.return_value = {409"Accept": "application/json",410"Content-Type": "application/xml;charset=UTF-8",411"User-Agent": "custom-agent/1.0 (python 3.13)",412}413414headers = remote_connection.get_remote_connection_headers(parse.urlparse("http://localhost:4444"))415416assert headers.get("User-Agent") == "custom-agent/1.0 (python 3.13)"417assert headers.get("Accept") == "application/json"418assert headers.get("Content-Type") == "application/xml;charset=UTF-8"419420421@patch("selenium.webdriver.remote.remote_connection.RemoteConnection._request")422def test_register_extra_headers(mock_request, remote_connection):423RemoteConnection.extra_headers = {"Foo": "bar"}424425mock_request.return_value = {"status": 200, "value": "OK"}426remote_connection.execute("newSession", {})427428mock_request.assert_called_once_with("POST", "http://localhost:4444/session", body="{}")429headers = RemoteConnection.get_remote_connection_headers(parse.urlparse("http://localhost:4444"), False)430assert headers["Foo"] == "bar"431432433@patch("selenium.webdriver.remote.remote_connection.RemoteConnection._request")434def test_register_extra_headers_via_client_config(mock_request):435client_config = ClientConfig(436remote_server_addr="http://localhost:4444",437extra_headers={438"Authorization": "AWS4-HMAC-SHA256",439"Credential": "abc/20200618/us-east-1/execute-api/aws4_request",440},441)442remote_connection = RemoteConnection(client_config=client_config)443444mock_request.return_value = {"status": 200, "value": "OK"}445remote_connection.execute("newSession", {})446447mock_request.assert_called_once_with("POST", "http://localhost:4444/session", body="{}")448headers = remote_connection.get_remote_connection_headers(parse.urlparse("http://localhost:4444"), False)449assert headers["Authorization"] == "AWS4-HMAC-SHA256"450assert headers["Credential"] == "abc/20200618/us-east-1/execute-api/aws4_request"451452453def test_backwards_compatibility_with_appium_connection():454# Keep backward compatibility for AppiumConnection - https://github.com/SeleniumHQ/selenium/issues/14694455client_config = ClientConfig(456remote_server_addr="http://localhost:4444", ca_certs="/path/to/cacert.pem", timeout=300457)458remote_connection = RemoteConnection(client_config=client_config)459assert remote_connection._ca_certs == "/path/to/cacert.pem"460assert remote_connection._timeout == 300461assert remote_connection._client_config == client_config462remote_connection.set_timeout(120)463assert remote_connection.get_timeout() == 120464remote_connection.set_certificate_bundle_path("/path/to/cacert2.pem")465assert remote_connection.get_certificate_bundle_path() == "/path/to/cacert2.pem"466467468def test_get_connection_manager_with_timeout_from_client_config():469remote_connection = RemoteConnection(remote_server_addr="http://localhost:4444", keep_alive=False)470remote_connection.set_timeout(10)471conn = remote_connection._get_connection_manager()472assert remote_connection.get_timeout() == 10473assert conn.connection_pool_kw["timeout"] == 10474assert isinstance(conn, PoolManager)475476477def test_connection_manager_with_timeout_via_client_config():478client_config = ClientConfig("http://remote", timeout=300)479remote_connection = RemoteConnection(client_config=client_config)480conn = remote_connection._get_connection_manager()481assert conn.connection_pool_kw["timeout"] == 300482assert isinstance(conn, PoolManager)483484485def test_get_connection_manager_with_ca_certs():486remote_connection = RemoteConnection(remote_server_addr="http://localhost:4444")487remote_connection.set_certificate_bundle_path("/path/to/cacert.pem")488conn = remote_connection._get_connection_manager()489assert conn.connection_pool_kw["timeout"] is None490assert conn.connection_pool_kw["cert_reqs"] == "CERT_REQUIRED"491assert conn.connection_pool_kw["ca_certs"] == "/path/to/cacert.pem"492assert isinstance(conn, PoolManager)493494495def test_connection_manager_with_ca_certs_via_client_config():496client_config = ClientConfig(remote_server_addr="http://localhost:4444", ca_certs="/path/to/cacert.pem")497remote_connection = RemoteConnection(client_config=client_config)498conn = remote_connection._get_connection_manager()499assert conn.connection_pool_kw["timeout"] is None500assert conn.connection_pool_kw["cert_reqs"] == "CERT_REQUIRED"501assert conn.connection_pool_kw["ca_certs"] == "/path/to/cacert.pem"502assert isinstance(conn, PoolManager)503504505def test_get_connection_manager_ignores_certificates():506remote_connection = RemoteConnection(507remote_server_addr="http://localhost:4444", keep_alive=False, ignore_certificates=True508)509remote_connection.set_timeout(10)510conn = remote_connection._get_connection_manager()511assert conn.connection_pool_kw["timeout"] == 10512assert conn.connection_pool_kw["cert_reqs"] == "CERT_NONE"513assert isinstance(conn, PoolManager)514remote_connection.reset_timeout()515assert remote_connection.get_timeout() is None516517518def test_connection_manager_ignores_certificates_via_client_config():519client_config = ClientConfig(remote_server_addr="http://localhost:4444", ignore_certificates=True, timeout=10)520remote_connection = RemoteConnection(client_config=client_config)521conn = remote_connection._get_connection_manager()522assert isinstance(conn, PoolManager)523assert conn.connection_pool_kw["timeout"] == 10524assert conn.connection_pool_kw["cert_reqs"] == "CERT_NONE"525526527def test_get_connection_manager_with_custom_args():528custom_args = {"init_args_for_pool_manager": {"retries": 3, "block": True}}529530remote_connection = RemoteConnection(531remote_server_addr="http://localhost:4444", keep_alive=False, init_args_for_pool_manager=custom_args532)533conn = remote_connection._get_connection_manager()534assert isinstance(conn, PoolManager)535assert isinstance(conn.connection_pool_kw["retries"], Retry)536assert conn.connection_pool_kw["retries"].total == 3537assert conn.connection_pool_kw["block"] is True538assert conn.connection_pool_kw["timeout"] is None539540541def test_connection_manager_with_custom_args_via_client_config():542retries = Retry(connect=2, read=2, redirect=2)543timeout = Timeout(connect=300, read=3600)544client_config = ClientConfig(545remote_server_addr="http://localhost:4444",546init_args_for_pool_manager={"init_args_for_pool_manager": {"retries": retries, "timeout": timeout}},547)548remote_connection = RemoteConnection(client_config=client_config)549conn = remote_connection._get_connection_manager()550assert isinstance(conn, PoolManager)551assert conn.connection_pool_kw["retries"] == retries552assert conn.connection_pool_kw["timeout"] == timeout553554555def test_proxy_auth_with_special_characters_url_encoded():556proxy_url = "http://user:passw%[email protected]:8080"557client_config = ClientConfig(558remote_server_addr="http://localhost:4444",559keep_alive=False,560proxy=Proxy({"proxyType": ProxyType.MANUAL, "httpProxy": proxy_url}),561)562remote_connection = RemoteConnection(client_config=client_config)563564proxy_without_auth, basic_auth = remote_connection._separate_http_proxy_auth()565566assert proxy_without_auth == "http://proxy.example.com:8080"567assert basic_auth == "user:passw%23rd" # Still URL-encoded568569conn = remote_connection._get_connection_manager()570assert isinstance(conn, ProxyManager)571572expected_auth = base64.b64encode(b"user:passw#rd").decode() # Decoded password573expected_headers = make_headers(proxy_basic_auth="user:passw#rd") # Unquoted password574575assert conn.proxy_headers == expected_headers576assert conn.proxy_headers["proxy-authorization"] == f"Basic {expected_auth}"577578579def test_proxy_auth_with_multiple_special_characters():580test_cases = [581("passw%23rd", "passw#rd"), # # character582("passw%40rd", "passw@rd"), # @ character583("passw%26rd", "passw&rd"), # & character584("passw%3Drd", "passw=rd"), # = character585("passw%2Brd", "passw+rd"), # + character586("passw%20rd", "passw rd"), # space character587("passw%21%40%23%24", "passw!@#$"), # Multiple special chars588]589590for encoded_password, decoded_password in test_cases:591proxy_url = f"http://testuser:{encoded_password}@proxy.example.com:8080"592client_config = ClientConfig(593remote_server_addr="http://localhost:4444",594keep_alive=False,595proxy=Proxy({"proxyType": ProxyType.MANUAL, "httpProxy": proxy_url}),596)597remote_connection = RemoteConnection(client_config=client_config)598599proxy_without_auth, basic_auth = remote_connection._separate_http_proxy_auth()600assert basic_auth == f"testuser:{encoded_password}"601602conn = remote_connection._get_connection_manager()603expected_auth = base64.b64encode(f"testuser:{decoded_password}".encode()).decode()604expected_headers = make_headers(proxy_basic_auth=f"testuser:{decoded_password}")605606assert conn.proxy_headers == expected_headers607assert conn.proxy_headers["proxy-authorization"] == f"Basic {expected_auth}"608609610