abhinavsingh / proxy.py

💫 Ngrok FRP Alternative • ⚡ Fast • 🪶 Lightweight • 0️⃣ Dependency • 🔌 Pluggable • 😈 TLS interception • 🔒 DNS-over-HTTPS • 🔥 Poor Man's VPN • ⏪ Reverse & ⏩ Forward • 👮🏿 "Proxy Server" framework • 🌐 "Web Server" framework • ➵ ➶ ➷ ➠ "PubSub" framework • 👷 "Work" acceptor & executor framework
https://abhinavsingh.com/proxy-py-a-lightweight-single-file-http-proxy-server-in-python/
BSD 3-Clause "New" or "Revised" License
2.91k stars 568 forks source link

Test failures with Python 3.12 #1428

Open mgorny opened 1 week ago

mgorny commented 1 week ago

Describe the bug When running the test suite with Python 3.12.4, I'm getting a bunch of test failures (plus these from #1426):

============================= test session starts ==============================
platform linux -- Python 3.12.4, pytest-8.1.1, pluggy-1.5.0 -- /tmp/proxy.py/.tox/py312/bin/python
cachedir: .pytest_cache
rootdir: /tmp/proxy.py
configfile: pytest.ini
testpaths: tests/
plugins: cov-5.0.0, anyio-4.4.0, xdist-3.5.0, mock-3.14.0, asyncio-0.21.1
asyncio: mode=Mode.STRICT
collecting ... collected 222 items

tests/common/test_flags.py::TestFlags::test_basic_auth_flag_is_base64_encoded PASSED [  0%]
tests/common/test_flags.py::TestFlags::test_load_plugin_from_args PASSED [  0%]
tests/common/test_flags.py::TestFlags::test_load_plugin_from_bytes PASSED [  1%]
tests/common/test_flags.py::TestFlags::test_load_plugin_from_class PASSED [  1%]
tests/common/test_flags.py::TestFlags::test_load_plugins_from_args PASSED [  2%]
tests/common/test_flags.py::TestFlags::test_load_plugins_from_bytes PASSED [  2%]
tests/common/test_flags.py::TestFlags::test_load_plugins_from_bytes_and_class PASSED [  3%]
tests/common/test_flags.py::TestFlags::test_load_plugins_from_class PASSED [  3%]
tests/common/test_flags.py::TestFlags::test_main_py2_exit PASSED         [  4%]
tests/common/test_flags.py::TestFlags::test_main_py3_runs PASSED         [  4%]
tests/common/test_flags.py::TestFlags::test_main_version PASSED          [  4%]
tests/common/test_flags.py::TestFlags::test_plugin_from_inner_class_by_name PASSED [  5%]
tests/common/test_flags.py::TestFlags::test_plugin_from_inner_class_by_type PASSED [  5%]
tests/common/test_flags.py::TestFlags::test_unique_plugin_from_args PASSED [  6%]
tests/common/test_flags.py::TestFlags::test_unique_plugin_from_bytes PASSED [  6%]
tests/common/test_flags.py::TestFlags::test_unique_plugin_from_class PASSED [  7%]
tests/common/test_pki.py::TestPki::test_extfile PASSED                   [  7%]
tests/common/test_pki.py::TestPki::test_extfile_no_ext PASSED            [  8%]
tests/common/test_pki.py::TestPki::test_gen_csr PASSED                   [  8%]
tests/common/test_pki.py::TestPki::test_gen_private_key PASSED           [  9%]
tests/common/test_pki.py::TestPki::test_gen_public_key PASSED            [  9%]
tests/common/test_pki.py::TestPki::test_get_ext_config PASSED            [  9%]
tests/common/test_pki.py::TestPki::test_run_openssl_command PASSED       [ 10%]
tests/common/test_pki.py::TestPki::test_sign_csr PASSED                  [ 10%]
tests/common/test_pki.py::TestPki::test_ssl_config PASSED                [ 11%]
tests/common/test_pki.py::TestPki::test_ssl_config_no_ext PASSED         [ 11%]
tests/common/test_text_bytes.py::TestTextBytes::test_bytes PASSED        [ 12%]
tests/common/test_text_bytes.py::TestTextBytes::test_bytes_int PASSED    [ 12%]
tests/common/test_text_bytes.py::TestTextBytes::test_bytes_nochange PASSED [ 13%]
tests/common/test_text_bytes.py::TestTextBytes::test_text PASSED         [ 13%]
tests/common/test_text_bytes.py::TestTextBytes::test_text_int PASSED     [ 13%]
tests/common/test_text_bytes.py::TestTextBytes::test_text_nochange PASSED [ 14%]
tests/common/test_utils.py::TestSocketConnectionUtils::test_context_manager PASSED [ 14%]
tests/common/test_utils.py::TestSocketConnectionUtils::test_decorator PASSED [ 15%]
tests/common/test_utils.py::TestSocketConnectionUtils::test_new_socket_connection_dual PASSED [ 15%]
tests/common/test_utils.py::TestSocketConnectionUtils::test_new_socket_connection_ipv4 PASSED [ 16%]
tests/common/test_utils.py::TestSocketConnectionUtils::test_new_socket_connection_ipv6 PASSED [ 16%]
tests/core/test_acceptor.py::TestAcceptor::test_accepts_client_from_server_socket PASSED [ 17%]
tests/core/test_acceptor.py::TestAcceptor::test_continues_when_no_events PASSED [ 17%]
tests/core/test_acceptor_pool.py::TestAcceptorPool::test_setup_and_shutdown PASSED [ 18%]
tests/core/test_conn_pool.py::TestConnectionPool::test_acquire_and_retain_and_reacquire PASSED [ 18%]
tests/core/test_conn_pool.py::TestConnectionPool::test_closed_connections_are_removed_on_release PASSED [ 18%]
tests/core/test_conn_pool.py::TestConnectionPoolAsync::test_get_events PASSED [ 19%]
tests/core/test_conn_pool.py::TestConnectionPoolAsync::test_handle_events PASSED [ 19%]
tests/core/test_connection.py::TestTcpConnection::testClosesIfNotClosed PASSED [ 20%]
tests/core/test_connection.py::TestTcpConnection::testFlushReturnsIfNoBuffer PASSED [ 20%]
tests/core/test_connection.py::TestTcpConnection::testNoOpIfAlreadyClosed PASSED [ 21%]
tests/core/test_connection.py::TestTcpConnection::testTcpClientRaisesTcpConnectionUninitializedException PASSED [ 21%]
tests/core/test_connection.py::TestTcpConnection::testTcpServerConnectionProperty PASSED [ 22%]
tests/core/test_connection.py::TestTcpConnection::testTcpServerEstablishesIPv4Connection PASSED [ 22%]
tests/core/test_connection.py::TestTcpConnection::testTcpServerEstablishesIPv6Connection PASSED [ 22%]
tests/core/test_connection.py::TestTcpConnection::testTcpServerRaisesTcpConnectionUninitializedException PASSED [ 23%]
tests/core/test_connection.py::TestTcpConnection::testTcpServerWillNotIgnoreDoubleConnectAttemptsSilently PASSED [ 23%]
tests/core/test_connection.py::TestTcpConnection::testThrowsKeyErrorIfNoConn PASSED [ 24%]
tests/core/test_event_dispatcher.py::TestEventDispatcher::test_empties_queue PASSED [ 24%]
tests/core/test_event_dispatcher.py::TestEventDispatcher::test_subscribe PASSED [ 25%]
tests/core/test_event_dispatcher.py::TestEventDispatcher::test_unsubscribe PASSED [ 25%]
tests/core/test_event_manager.py::TestEventManager::test_setup_and_teardown PASSED [ 26%]
tests/core/test_event_queue.py::TestCoreEvent::test_publish PASSED       [ 26%]
tests/core/test_event_queue.py::TestCoreEvent::test_subscribe PASSED     [ 27%]
tests/core/test_event_queue.py::TestCoreEvent::test_unsubscribe PASSED   [ 27%]
tests/core/test_event_subscriber.py::TestEventSubscriber::test_event_subscriber PASSED [ 27%]
tests/core/test_listener.py::TestListener::test_setup_and_teardown PASSED [ 28%]
tests/core/test_listener.py::TestListener::test_unix_path_listener PASSED [ 28%]
tests/core/test_listener_pool.py::TestListenerPool::test_multi_listener PASSED [ 29%]
tests/core/test_listener_pool.py::TestListenerPool::test_setup_and_teardown PASSED [ 29%]
tests/core/test_listener_pool.py::TestListenerPool::test_unix_socket_listener PASSED [ 30%]
tests/http/exceptions/test_http_proxy_auth_failed.py::TestHttpProxyAuthFailed::test_proxy_auth_fails_without_cred PASSED [ 30%]
tests/http/exceptions/test_http_proxy_auth_failed.py::TestHttpProxyAuthFailed::test_proxy_auth_fails_with_invalid_cred PASSED [ 31%]
tests/http/exceptions/test_http_proxy_auth_failed.py::TestHttpProxyAuthFailed::test_proxy_auth_works_with_valid_cred PASSED [ 31%]
tests/http/exceptions/test_http_proxy_auth_failed.py::TestHttpProxyAuthFailed::test_proxy_auth_works_with_mixed_case_basic_string PASSED [ 31%]
tests/http/exceptions/test_http_request_rejected.py::TestHttpRequestRejected::test_body_response PASSED [ 32%]
tests/http/exceptions/test_http_request_rejected.py::TestHttpRequestRejected::test_empty_response PASSED [ 32%]
tests/http/exceptions/test_http_request_rejected.py::TestHttpRequestRejected::test_status_code_response PASSED [ 33%]
tests/http/parser/test_chunk_parser.py::TestChunkParser::test_chunk_parse_basic PASSED [ 33%]
tests/http/parser/test_chunk_parser.py::TestChunkParser::test_chunk_parse_issue_27 PASSED [ 34%]
tests/http/parser/test_chunk_parser.py::TestChunkParser::test_to_chunks PASSED [ 34%]
tests/http/parser/test_http_parser.py::TestHttpParser::test_build_header PASSED [ 35%]
tests/http/parser/test_http_parser.py::TestHttpParser::test_build_request PASSED [ 35%]
tests/http/parser/test_http_parser.py::TestHttpParser::test_build_response PASSED [ 36%]
tests/http/parser/test_http_parser.py::TestHttpParser::test_build_response_adds_content_length_header PASSED [ 36%]
tests/http/parser/test_http_parser.py::TestHttpParser::test_cannot_parse_sip_protocol PASSED [ 36%]
tests/http/parser/test_http_parser.py::TestHttpParser::test_chunked_request_parse PASSED [ 37%]
tests/http/parser/test_http_parser.py::TestHttpParser::test_chunked_response_parse PASSED [ 37%]
tests/http/parser/test_http_parser.py::TestHttpParser::test_connect_request_with_crlf_as_separate_chunk PASSED [ 38%]
tests/http/parser/test_http_parser.py::TestHttpParser::test_connect_request_without_host_header_request_parse PASSED [ 38%]
tests/http/parser/test_http_parser.py::TestHttpParser::test_find_line PASSED [ 39%]
tests/http/parser/test_http_parser.py::TestHttpParser::test_find_line_returns_None PASSED [ 39%]
tests/http/parser/test_http_parser.py::TestHttpParser::test_get_full_parse PASSED [ 40%]
tests/http/parser/test_http_parser.py::TestHttpParser::test_get_partial_parse1 PASSED [ 40%]
tests/http/parser/test_http_parser.py::TestHttpParser::test_get_partial_parse2 PASSED [ 40%]
tests/http/parser/test_http_parser.py::TestHttpParser::test_has_header PASSED [ 41%]
tests/http/parser/test_http_parser.py::TestHttpParser::test_header_raises PASSED [ 41%]
tests/http/parser/test_http_parser.py::TestHttpParser::test_invalid_ipv6_in_request_line PASSED [ 42%]
tests/http/parser/test_http_parser.py::TestHttpParser::test_is_http_1_1_keep_alive PASSED [ 42%]
tests/http/parser/test_http_parser.py::TestHttpParser::test_is_http_1_1_keep_alive_with_non_close_connection_header PASSED [ 43%]
tests/http/parser/test_http_parser.py::TestHttpParser::test_is_not_http_1_1_keep_alive_for_http_1_0 PASSED [ 43%]
tests/http/parser/test_http_parser.py::TestHttpParser::test_is_not_http_1_1_keep_alive_with_close_header PASSED [ 44%]
tests/http/parser/test_http_parser.py::TestHttpParser::test_is_safe_against_malicious_requests PASSED [ 44%]
tests/http/parser/test_http_parser.py::TestHttpParser::test_issue_127 PASSED [ 45%]
tests/http/parser/test_http_parser.py::TestHttpParser::test_issue_398 PASSED [ 45%]
tests/http/parser/test_http_parser.py::TestHttpParser::test_line_rcvd_to_rcving_headers_state_change PASSED [ 45%]
tests/http/parser/test_http_parser.py::TestHttpParser::test_paramiko_doc PASSED [ 46%]
tests/http/parser/test_http_parser.py::TestHttpParser::test_parses_icap_protocol PASSED [ 46%]
tests/http/parser/test_http_parser.py::TestHttpParser::test_pipelined_chunked_response_parse PASSED [ 47%]
tests/http/parser/test_http_parser.py::TestHttpParser::test_pipelined_response_parse PASSED [ 47%]
tests/http/parser/test_http_parser.py::TestHttpParser::test_post_full_parse PASSED [ 48%]
tests/http/parser/test_http_parser.py::TestHttpParser::test_post_partial_parse PASSED [ 48%]
tests/http/parser/test_http_parser.py::TestHttpParser::test_proxy_protocol PASSED [ 49%]
tests/http/parser/test_http_parser.py::TestHttpParser::test_proxy_protocol_not_for_response_parser PASSED [ 49%]
tests/http/parser/test_http_parser.py::TestHttpParser::test_request_factory PASSED [ 50%]
tests/http/parser/test_http_parser.py::TestHttpParser::test_request_parse_without_content_length PASSED [ 50%]
tests/http/parser/test_http_parser.py::TestHttpParser::test_response_factory PASSED [ 50%]
tests/http/parser/test_http_parser.py::TestHttpParser::test_response_parse PASSED [ 51%]
tests/http/parser/test_http_parser.py::TestHttpParser::test_response_parse_without_content_length PASSED [ 51%]
tests/http/parser/test_http_parser.py::TestHttpParser::test_response_partial_parse PASSED [ 52%]
tests/http/parser/test_http_parser.py::TestHttpParser::test_set_host_port_raises PASSED [ 52%]
tests/http/parser/test_http_parser.py::TestHttpParser::test_unicode_character_domain_connect PASSED [ 53%]
tests/http/parser/test_http_parser.py::TestHttpParser::test_urlparse PASSED [ 53%]
tests/http/parser/test_http_parser.py::TestHttpParser::test_urlparse_on_invalid_connect_request PASSED [ 54%]
tests/http/parser/test_http_parser.py::TestHttpParser::test_valid_ipv6_in_request_line PASSED [ 54%]
tests/http/parser/test_proxy_protocol.py::TestProxyProtocol::test_unknown_value_error PASSED [ 54%]
tests/http/parser/test_proxy_protocol.py::TestProxyProtocol::test_v1 PASSED [ 55%]
tests/http/parser/test_proxy_protocol.py::TestProxyProtocol::test_v1_example_from_spec PASSED [ 55%]
tests/http/parser/test_proxy_protocol.py::TestProxyProtocol::test_v1_unknown_with_no_src_dst PASSED [ 56%]
tests/http/parser/test_proxy_protocol.py::TestProxyProtocol::test_v1_worst_case_ipv4_from_spec PASSED [ 56%]
tests/http/parser/test_proxy_protocol.py::TestProxyProtocol::test_v1_worst_case_ipv6_from_spec PASSED [ 57%]
tests/http/parser/test_proxy_protocol.py::TestProxyProtocol::test_v1_worst_case_unknown_from_spec PASSED [ 57%]
tests/http/parser/test_proxy_protocol.py::TestProxyProtocol::test_v2_not_implemented PASSED [ 58%]
tests/http/parser/test_tls_parser.py::TestTlsParser::test_parse_client_hello PASSED [ 58%]
tests/http/parser/test_tls_parser.py::TestTlsParser::test_parse_server_hello PASSED [ 59%]
tests/http/proxy/test_http2.py::TestHttp2WithProxy::test_http2_via_proxy PASSED [ 59%]
tests/http/proxy/test_http_proxy.py::TestHttpProxyPlugin::test_proxy_plugin_not_initialized_unless_first_request_completes PASSED [ 59%]
tests/http/proxy/test_http_proxy.py::TestHttpProxyPlugin::test_proxy_plugin_on_and_before_upstream_connection PASSED [ 60%]
tests/http/proxy/test_http_proxy.py::TestHttpProxyPlugin::test_proxy_plugin_before_upstream_connection_can_teardown PASSED [ 60%]
tests/http/proxy/test_http_proxy.py::TestHttpProxyPlugin::test_proxy_plugin_plugins_can_teardown_from_write_to_descriptors PASSED [ 61%]
tests/http/proxy/test_http_proxy.py::TestHttpProxyPlugin::test_proxy_plugin_retries_on_ssl_want_write_error PASSED [ 61%]
tests/http/proxy/test_http_proxy.py::TestHttpProxyPlugin::test_proxy_plugin_broken_pipe_error_on_write_will_teardown PASSED [ 62%]
tests/http/proxy/test_http_proxy.py::TestHttpProxyPlugin::test_proxy_plugin_plugins_can_teardown_from_read_from_descriptors PASSED [ 62%]
tests/http/proxy/test_http_proxy.py::TestHttpProxyPlugin::test_proxy_plugin_retries_on_ssl_want_read_error PASSED [ 63%]
tests/http/proxy/test_http_proxy.py::TestHttpProxyPlugin::test_proxy_plugin_timeout_error_on_read_will_teardown PASSED [ 63%]
tests/http/proxy/test_http_proxy.py::TestHttpProxyPlugin::test_proxy_plugin_invokes_handle_pipeline_response PASSED [ 63%]
tests/http/proxy/test_http_proxy.py::TestHttpProxyPlugin::test_proxy_plugin_invokes_on_access_log PASSED [ 64%]
tests/http/proxy/test_http_proxy.py::TestHttpProxyPlugin::test_proxy_plugin_skips_server_teardown_when_client_closes_and_server_never_initialized PASSED [ 64%]
tests/http/proxy/test_http_proxy.py::TestHttpProxyPlugin::test_proxy_plugin_invokes_handle_client_data PASSED [ 65%]
tests/http/proxy/test_http_proxy.py::TestHttpProxyPlugin::test_proxy_plugin_handles_pipeline_response PASSED [ 65%]
tests/http/proxy/test_http_proxy.py::TestHttpProxyPlugin::test_proxy_plugin_invokes_resolve_dns PASSED [ 66%]
tests/http/proxy/test_http_proxy.py::TestHttpProxyPlugin::test_proxy_plugin_require_both_host_port_to_connect PASSED [ 66%]
tests/http/proxy/test_http_proxy_tls_interception.py::TestHttpProxyTlsInterception::test_e2e FAILED [ 67%]
tests/http/test_protocol_handler.py::TestHttpProtocolHandlerWithoutServerMock::test_proxy_connection_failed PASSED [ 67%]
tests/http/test_protocol_handler.py::TestHttpProtocolHandlerWithoutServerMock::test_proxy_authentication_failed PASSED [ 68%]
tests/http/test_protocol_handler.py::TestHttpProtocolHandlerWithoutServerMock::test_proxy_bails_out_for_unknown_schemes PASSED [ 68%]
tests/http/test_protocol_handler.py::TestHttpProtocolHandlerWithoutServerMock::test_proxy_bails_out_for_sip_request_lines PASSED [ 68%]
tests/http/test_protocol_handler.py::TestHttpProtocolHandler::test_http_get PASSED [ 69%]
tests/http/test_protocol_handler.py::TestHttpProtocolHandler::test_http_tunnel PASSED [ 69%]
tests/http/test_protocol_handler.py::TestHttpProtocolHandler::test_authenticated_proxy_http_get PASSED [ 70%]
tests/http/test_protocol_handler.py::TestHttpProtocolHandler::test_authenticated_proxy_http_tunnel PASSED [ 70%]
tests/http/test_responses.py::TestResponses::test_basic PASSED           [ 71%]
tests/http/test_responses.py::TestResponses::test_chunked_with_compression PASSED [ 71%]
tests/http/test_responses.py::TestResponses::test_chunked_without_compression PASSED [ 72%]
tests/http/test_responses.py::TestResponses::test_close_header PASSED    [ 72%]
tests/http/test_responses.py::TestResponses::test_compression PASSED     [ 72%]
tests/http/test_url.py::TestUrl::test_any_scheme_suffix PASSED           [ 73%]
tests/http/test_url.py::TestUrl::test_assert_raises_for_unknown_schemes PASSED [ 73%]
tests/http/test_url.py::TestUrl::test_full_url PASSED                    [ 74%]
tests/http/test_url.py::TestUrl::test_http_ipv6_url PASSED               [ 74%]
tests/http/test_url.py::TestUrl::test_http_ipv6_with_port_url PASSED     [ 75%]
tests/http/test_url.py::TestUrl::test_http_proxy_url PASSED              [ 75%]
tests/http/test_url.py::TestUrl::test_https_connect_url PASSED           [ 76%]
tests/http/test_url.py::TestUrl::test_https_connect_with_ipv6_malformed_url PASSED [ 76%]
tests/http/test_url.py::TestUrl::test_https_connect_with_ipv6_url PASSED [ 77%]
tests/http/test_url.py::TestUrl::test_just_domain_name_url PASSED        [ 77%]
tests/http/test_url.py::TestUrl::test_no_scheme_suffix PASSED            [ 77%]
tests/http/test_url.py::TestUrl::test_no_trailing_slash_url PASSED       [ 78%]
tests/http/test_url.py::TestUrl::test_trailing_slash_url PASSED          [ 78%]
tests/http/test_url.py::TestUrl::test_unicode_url PASSED                 [ 79%]
tests/http/test_url.py::TestUrl::test_url_str PASSED                     [ 79%]
tests/http/test_url.py::TestUrl::test_username_password PASSED           [ 80%]
tests/http/test_url.py::TestUrl::test_username_password_without_proto_prefix PASSED [ 80%]
tests/http/test_url.py::TestUrl::test_web_server_url PASSED              [ 81%]
tests/http/web/test_web_server.py::test_on_client_connection_called_on_teardown PASSED [ 81%]
tests/http/web/test_web_server.py::TestWebServerPluginWithPacFilePlugin::test_pac_file_served_from_disk[/tmp/proxy.py/helper/proxy.pac] FAILED [ 81%]
tests/http/web/test_web_server.py::TestWebServerPluginWithPacFilePlugin::test_pac_file_served_from_disk[function FindProxyForURL(url, host) { return "PROXY localhost:8899; DIRECT"; }] FAILED [ 82%]
tests/http/web/test_web_server.py::TestStaticWebServerPlugin::test_static_web_server_serves PASSED [ 82%]
tests/http/web/test_web_server.py::TestStaticWebServerPlugin::test_static_web_server_serves_404 PASSED [ 83%]
tests/http/web/test_web_server.py::TestWebServerPlugin::test_default_web_server_returns_404 PASSED [ 83%]
tests/http/websocket/test_websocket_client.py::TestWebsocketClient::test_handshake_success PASSED [ 84%]
tests/http/websocket/test_websocket_client.py::TestWebsocketClient::test_run PASSED [ 84%]
tests/http/websocket/test_websocket_client.py::TestWebsocketClient::test_send_recv_frames_success PASSED [ 85%]
tests/http/websocket/test_websocket_frame.py::TestWebsocketFrame::test_build_with_mask PASSED [ 85%]
tests/http/websocket/test_websocket_frame.py::TestWebsocketFrame::test_parse_with_mask PASSED [ 86%]
tests/plugin/test_http_proxy_plugins.py::TestHttpProxyPluginExamples::test_modify_post_data_plugin[test_modify_post_data_plugin] PASSED [ 86%]
tests/plugin/test_http_proxy_plugins.py::TestHttpProxyPluginExamples::test_proposed_rest_api_plugin[test_proposed_rest_api_plugin] PASSED [ 86%]
tests/plugin/test_http_proxy_plugins.py::TestHttpProxyPluginExamples::test_redirect_to_custom_server_plugin[test_redirect_to_custom_server_plugin] PASSED [ 87%]
tests/plugin/test_http_proxy_plugins.py::TestHttpProxyPluginExamples::test_redirect_to_custom_server_plugin_skips_https[test_redirect_to_custom_server_plugin] PASSED [ 87%]
tests/plugin/test_http_proxy_plugins.py::TestHttpProxyPluginExamples::test_filter_by_upstream_host_plugin[test_filter_by_upstream_host_plugin] PASSED [ 88%]
tests/plugin/test_http_proxy_plugins.py::TestHttpProxyPluginExamples::test_man_in_the_middle_plugin[test_man_in_the_middle_plugin] PASSED [ 88%]
tests/plugin/test_http_proxy_plugins.py::TestHttpProxyPluginExamples::test_filter_by_url_regex_plugin[test_filter_by_url_regex_plugin] PASSED [ 89%]
tests/plugin/test_http_proxy_plugins.py::TestHttpProxyPluginExamples::test_shortlink_plugin[test_shortlink_plugin] PASSED [ 89%]
tests/plugin/test_http_proxy_plugins.py::TestHttpProxyPluginExamples::test_shortlink_plugin_unknown[test_shortlink_plugin] PASSED [ 90%]
tests/plugin/test_http_proxy_plugins.py::TestHttpProxyPluginExamples::test_shortlink_plugin_external[test_shortlink_plugin] PASSED [ 90%]
tests/plugin/test_http_proxy_plugins.py::TestHttpProxyPluginExamples::test_auth_plugin[test_auth_plugin] PASSED [ 90%]
tests/plugin/test_http_proxy_plugins.py::TestHttpProxyPluginExamples::test_auth_plugin_bypass[test_auth_plugin] PASSED [ 91%]
tests/plugin/test_http_proxy_plugins_with_tls_interception.py::TestHttpProxyPluginExamplesWithTlsInterception::test_modify_post_data_plugin[test_modify_post_data_plugin] ERROR [ 91%]
tests/plugin/test_http_proxy_plugins_with_tls_interception.py::TestHttpProxyPluginExamplesWithTlsInterception::test_man_in_the_middle_plugin[test_man_in_the_middle_plugin] ERROR [ 92%]
tests/socks/test_handler.py::TestHttpProtocolHandlerWithoutServerMock::test PASSED [ 92%]
tests/socks/test_packet.py::TestSocks4Packet::test_pack PASSED           [ 93%]
tests/socks/test_packet.py::TestSocks4Packet::test_parse PASSED          [ 93%]
tests/test_main.py::TestMain::test_enable_dashboard PASSED               [ 94%]
tests/test_main.py::TestMain::test_enable_devtools PASSED                [ 94%]
tests/test_main.py::TestMain::test_enable_events PASSED                  [ 95%]
tests/test_main.py::TestMain::test_enable_ssh_tunnel PASSED              [ 95%]
tests/test_main.py::TestMain::test_entry_point PASSED                    [ 95%]
tests/test_main.py::TestMain::test_main_with_no_flags PASSED             [ 96%]
tests/test_main.py::TestProxyContextManager::test_proxy_context_manager PASSED [ 96%]
tests/test_set_open_file_limit.py::TestSetOpenFileLimit::test_set_open_file_limit PASSED [ 97%]
tests/test_set_open_file_limit.py::TestSetOpenFileLimit::test_set_open_file_limit_not_called PASSED [ 97%]
tests/test_set_open_file_limit.py::TestSetOpenFileLimit::test_set_open_file_limit_not_called_coz_upper_bound_check PASSED [ 98%]
tests/testing/test_embed.py::TestProxyPyEmbedded::test_proxy_no_vcr PASSED [ 98%]
tests/testing/test_embed.py::TestProxyPyEmbedded::test_proxy_vcr PASSED  [ 99%]
tests/testing/test_embed.py::TestProxyPyEmbedded::test_with_proxy PASSED [ 99%]
tests/testing/test_test_case.py::TestTestCase::test_wait_for_server_raises_timeout_error PASSED [100%]

==================================== ERRORS ====================================
_ ERROR at setup of TestHttpProxyPluginExamplesWithTlsInterception.test_modify_post_data_plugin[test_modify_post_data_plugin] _

self = <tests.plugin.test_http_proxy_plugins_with_tls_interception.TestHttpProxyPluginExamplesWithTlsInterception object at 0x7ff0b891d3a0>
request = <SubRequest '_setUp' for <Function test_modify_post_data_plugin[test_modify_post_data_plugin]>>
mocker = <pytest_mock.plugin.MockerFixture object at 0x7ff0b64bb3e0>

    @pytest.fixture(autouse=True)   # type: ignore[misc]
    def _setUp(self, request: Any, mocker: MockerFixture) -> None:
        self.mock_socket_dup = mocker.patch('socket.dup')
        self.mock_selector = mocker.patch('selectors.DefaultSelector')
        self.mock_sign_csr = mocker.patch('proxy.http.proxy.server.sign_csr')
        self.mock_gen_csr = mocker.patch('proxy.http.proxy.server.gen_csr')
        self.mock_gen_public_key = mocker.patch(
            'proxy.http.proxy.server.gen_public_key',
        )
        self.mock_server_conn = mocker.patch(
            'proxy.http.proxy.server.TcpServerConnection',
        )
        self.mock_ssl_context = mocker.patch('ssl.create_default_context')
>       self.mock_ssl_wrap = mocker.patch('ssl.wrap_socket')

mocker     = <pytest_mock.plugin.MockerFixture object at 0x7ff0b64bb3e0>
request    = <SubRequest '_setUp' for <Function test_modify_post_data_plugin[test_modify_post_data_plugin]>>
self       = <tests.plugin.test_http_proxy_plugins_with_tls_interception.TestHttpProxyPluginExamplesWithTlsInterception object at 0x7ff0b891d3a0>

tests/plugin/test_http_proxy_plugins_with_tls_interception.py:49: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
.tox/py312/lib/python3.12/site-packages/pytest_mock/plugin.py:440: in __call__
    return self._start_patch(
        autospec   = None
        create     = False
        kwargs     = {}
        new        = sentinel.DEFAULT
        new_callable = None
        self       = <pytest_mock.plugin.MockerFixture._Patcher object at 0x7ff0b64b8620>
        spec       = None
        spec_set   = None
        target     = 'ssl.wrap_socket'
.tox/py312/lib/python3.12/site-packages/pytest_mock/plugin.py:258: in _start_patch
    mocked: MockType = p.start()
        args       = ('ssl.wrap_socket',)
        kwargs     = {'autospec': None, 'create': False, 'new': sentinel.DEFAULT, 'new_callable': None, ...}
        mock_func  = <function patch at 0x7ff0b9495260>
        p          = <unittest.mock._patch object at 0x7ff0b5e0c170>
        self       = <pytest_mock.plugin.MockerFixture._Patcher object at 0x7ff0b64b8620>
        warn_on_mock_enter = True
/usr/lib/python3.12/unittest/mock.py:1606: in start
    result = self.__enter__()
        self       = <unittest.mock._patch object at 0x7ff0b5e0c170>
/usr/lib/python3.12/unittest/mock.py:1458: in __enter__
    original, local = self.get_original()
        autospec   = None
        kwargs     = {}
        new        = sentinel.DEFAULT
        new_callable = None
        self       = <unittest.mock._patch object at 0x7ff0b5e0c170>
        spec       = None
        spec_set   = None
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <unittest.mock._patch object at 0x7ff0b5e0c170>

    def get_original(self):
        target = self.getter()
        name = self.attribute

        original = DEFAULT
        local = False

        try:
            original = target.__dict__[name]
        except (AttributeError, KeyError):
            original = getattr(target, name, DEFAULT)
        else:
            local = True

        if name in _builtins and isinstance(target, ModuleType):
            self.create = True

        if not self.create and original is DEFAULT:
>           raise AttributeError(
                "%s does not have the attribute %r" % (target, name)
            )
E           AttributeError: <module 'ssl' from '/usr/lib/python3.12/ssl.py'> does not have the attribute 'wrap_socket'

local      = False
name       = 'wrap_socket'
original   = sentinel.DEFAULT
self       = <unittest.mock._patch object at 0x7ff0b5e0c170>
target     = <module 'ssl' from '/usr/lib/python3.12/ssl.py'>

/usr/lib/python3.12/unittest/mock.py:1431: AttributeError
_ ERROR at setup of TestHttpProxyPluginExamplesWithTlsInterception.test_man_in_the_middle_plugin[test_man_in_the_middle_plugin] _

self = <tests.plugin.test_http_proxy_plugins_with_tls_interception.TestHttpProxyPluginExamplesWithTlsInterception object at 0x7ff0b891d5e0>
request = <SubRequest '_setUp' for <Function test_man_in_the_middle_plugin[test_man_in_the_middle_plugin]>>
mocker = <pytest_mock.plugin.MockerFixture object at 0x7ff0b64e0740>

    @pytest.fixture(autouse=True)   # type: ignore[misc]
    def _setUp(self, request: Any, mocker: MockerFixture) -> None:
        self.mock_socket_dup = mocker.patch('socket.dup')
        self.mock_selector = mocker.patch('selectors.DefaultSelector')
        self.mock_sign_csr = mocker.patch('proxy.http.proxy.server.sign_csr')
        self.mock_gen_csr = mocker.patch('proxy.http.proxy.server.gen_csr')
        self.mock_gen_public_key = mocker.patch(
            'proxy.http.proxy.server.gen_public_key',
        )
        self.mock_server_conn = mocker.patch(
            'proxy.http.proxy.server.TcpServerConnection',
        )
        self.mock_ssl_context = mocker.patch('ssl.create_default_context')
>       self.mock_ssl_wrap = mocker.patch('ssl.wrap_socket')

mocker     = <pytest_mock.plugin.MockerFixture object at 0x7ff0b64e0740>
request    = <SubRequest '_setUp' for <Function test_man_in_the_middle_plugin[test_man_in_the_middle_plugin]>>
self       = <tests.plugin.test_http_proxy_plugins_with_tls_interception.TestHttpProxyPluginExamplesWithTlsInterception object at 0x7ff0b891d5e0>

tests/plugin/test_http_proxy_plugins_with_tls_interception.py:49: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
.tox/py312/lib/python3.12/site-packages/pytest_mock/plugin.py:440: in __call__
    return self._start_patch(
        autospec   = None
        create     = False
        kwargs     = {}
        new        = sentinel.DEFAULT
        new_callable = None
        self       = <pytest_mock.plugin.MockerFixture._Patcher object at 0x7ff0b64bb3b0>
        spec       = None
        spec_set   = None
        target     = 'ssl.wrap_socket'
.tox/py312/lib/python3.12/site-packages/pytest_mock/plugin.py:258: in _start_patch
    mocked: MockType = p.start()
        args       = ('ssl.wrap_socket',)
        kwargs     = {'autospec': None, 'create': False, 'new': sentinel.DEFAULT, 'new_callable': None, ...}
        mock_func  = <function patch at 0x7ff0b9495260>
        p          = <unittest.mock._patch object at 0x7ff0b5eae210>
        self       = <pytest_mock.plugin.MockerFixture._Patcher object at 0x7ff0b64bb3b0>
        warn_on_mock_enter = True
/usr/lib/python3.12/unittest/mock.py:1606: in start
    result = self.__enter__()
        self       = <unittest.mock._patch object at 0x7ff0b5eae210>
/usr/lib/python3.12/unittest/mock.py:1458: in __enter__
    original, local = self.get_original()
        autospec   = None
        kwargs     = {}
        new        = sentinel.DEFAULT
        new_callable = None
        self       = <unittest.mock._patch object at 0x7ff0b5eae210>
        spec       = None
        spec_set   = None
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <unittest.mock._patch object at 0x7ff0b5eae210>

    def get_original(self):
        target = self.getter()
        name = self.attribute

        original = DEFAULT
        local = False

        try:
            original = target.__dict__[name]
        except (AttributeError, KeyError):
            original = getattr(target, name, DEFAULT)
        else:
            local = True

        if name in _builtins and isinstance(target, ModuleType):
            self.create = True

        if not self.create and original is DEFAULT:
>           raise AttributeError(
                "%s does not have the attribute %r" % (target, name)
            )
E           AttributeError: <module 'ssl' from '/usr/lib/python3.12/ssl.py'> does not have the attribute 'wrap_socket'

local      = False
name       = 'wrap_socket'
original   = sentinel.DEFAULT
self       = <unittest.mock._patch object at 0x7ff0b5eae210>
target     = <module 'ssl' from '/usr/lib/python3.12/ssl.py'>

/usr/lib/python3.12/unittest/mock.py:1431: AttributeError
=================================== FAILURES ===================================
____________________ TestHttpProxyTlsInterception.test_e2e _____________________

self = <tests.http.proxy.test_http_proxy_tls_interception.TestHttpProxyTlsInterception object at 0x7ff0b8a82180>
mocker = <pytest_mock.plugin.MockerFixture object at 0x7ff0b7130590>

    @pytest.mark.asyncio    # type: ignore[misc]
    async def test_e2e(self, mocker: MockerFixture) -> None:
        host, port = uuid.uuid4().hex, 443
        netloc = '{0}:{1}'.format(host, port)

        self.mock_socket_dup = mocker.patch('socket.dup')
        self.mock_selector = mocker.patch('selectors.DefaultSelector')
        self.mock_sign_csr = mocker.patch('proxy.http.proxy.server.sign_csr')
        self.mock_gen_csr = mocker.patch('proxy.http.proxy.server.gen_csr')
        self.mock_gen_public_key = mocker.patch(
            'proxy.http.proxy.server.gen_public_key',
        )
        self.mock_server_conn = mocker.patch(
            'proxy.http.proxy.server.TcpServerConnection',
        )
        self.mock_sign_csr.return_value = True
        self.mock_gen_csr.return_value = True
        self.mock_gen_public_key.return_value = True

        self.fileno = 10
        self.mock_socket_dup.side_effect = lambda fd: fd

        # Used for server side wrapping
        self.mock_ssl_context = mocker.patch('ssl.create_default_context')
        upstream_tls_sock = mock.MagicMock(spec=ssl.SSLSocket)
        self.mock_ssl_context.return_value.wrap_socket.return_value = upstream_tls_sock

        # Used for client wrapping
>       self.mock_ssl_wrap = mocker.patch('ssl.wrap_socket')

host       = 'd5d1476d8dee4c908bd2fa99210cf7b7'
mocker     = <pytest_mock.plugin.MockerFixture object at 0x7ff0b7130590>
netloc     = 'd5d1476d8dee4c908bd2fa99210cf7b7:443'
port       = 443
self       = <tests.http.proxy.test_http_proxy_tls_interception.TestHttpProxyTlsInterception object at 0x7ff0b8a82180>
upstream_tls_sock = <MagicMock name='create_default_context().wrap_socket()' spec='SSLSocket' id='140671830047968'>

tests/http/proxy/test_http_proxy_tls_interception.py:65: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
.tox/py312/lib/python3.12/site-packages/pytest_mock/plugin.py:440: in __call__
    return self._start_patch(
        autospec   = None
        create     = False
        kwargs     = {}
        new        = sentinel.DEFAULT
        new_callable = None
        self       = <pytest_mock.plugin.MockerFixture._Patcher object at 0x7ff0b716f8c0>
        spec       = None
        spec_set   = None
        target     = 'ssl.wrap_socket'
.tox/py312/lib/python3.12/site-packages/pytest_mock/plugin.py:258: in _start_patch
    mocked: MockType = p.start()
        args       = ('ssl.wrap_socket',)
        kwargs     = {'autospec': None, 'create': False, 'new': sentinel.DEFAULT, 'new_callable': None, ...}
        mock_func  = <function patch at 0x7ff0b9495260>
        p          = <unittest.mock._patch object at 0x7ff0b6763170>
        self       = <pytest_mock.plugin.MockerFixture._Patcher object at 0x7ff0b716f8c0>
        warn_on_mock_enter = True
/usr/lib/python3.12/unittest/mock.py:1606: in start
    result = self.__enter__()
        self       = <unittest.mock._patch object at 0x7ff0b6763170>
/usr/lib/python3.12/unittest/mock.py:1458: in __enter__
    original, local = self.get_original()
        autospec   = None
        kwargs     = {}
        new        = sentinel.DEFAULT
        new_callable = None
        self       = <unittest.mock._patch object at 0x7ff0b6763170>
        spec       = None
        spec_set   = None
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <unittest.mock._patch object at 0x7ff0b6763170>

    def get_original(self):
        target = self.getter()
        name = self.attribute

        original = DEFAULT
        local = False

        try:
            original = target.__dict__[name]
        except (AttributeError, KeyError):
            original = getattr(target, name, DEFAULT)
        else:
            local = True

        if name in _builtins and isinstance(target, ModuleType):
            self.create = True

        if not self.create and original is DEFAULT:
>           raise AttributeError(
                "%s does not have the attribute %r" % (target, name)
            )
E           AttributeError: <module 'ssl' from '/usr/lib/python3.12/ssl.py'> does not have the attribute 'wrap_socket'

local      = False
name       = 'wrap_socket'
original   = sentinel.DEFAULT
self       = <unittest.mock._patch object at 0x7ff0b6763170>
target     = <module 'ssl' from '/usr/lib/python3.12/ssl.py'>

/usr/lib/python3.12/unittest/mock.py:1431: AttributeError
_ TestWebServerPluginWithPacFilePlugin.test_pac_file_served_from_disk[/tmp/proxy.py/helper/proxy.pac] _

self = <tests.http.web.test_web_server.TestWebServerPluginWithPacFilePlugin object at 0x7ff0b8ab2e40>

    @pytest.mark.asyncio    # type: ignore[misc]
    async def test_pac_file_served_from_disk(self) -> None:
        await self.protocol_handler._run_once()
        self.assertEqual(
            self.protocol_handler.request.state,
            httpParserStates.COMPLETE,
        )
>       self._conn.send.called_once_with(
            build_http_response(
                200,
                reason=b'OK',
                headers={
                    b'Content-Type': b'application/x-ns-proxy-autoconfig',
                },
                body=self.expected_response,
                conn_close=True,
            ),
        )

self       = <tests.http.web.test_web_server.TestWebServerPluginWithPacFilePlugin object at 0x7ff0b8ab2e40>

tests/http/web/test_web_server.py:183: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <MagicMock name='socket().send' id='140671823548960'>
name = 'called_once_with'

    def __getattr__(self, name):
        if name in {'_mock_methods', '_mock_unsafe'}:
            raise AttributeError(name)
        elif self._mock_methods is not None:
            if name not in self._mock_methods or name in _all_magics:
                raise AttributeError("Mock object has no attribute %r" % name)
        elif _is_magic(name):
            raise AttributeError(name)
        if not self._mock_unsafe and (not self._mock_methods or name not in self._mock_methods):
            if name.startswith(('assert', 'assret', 'asert', 'aseert', 'assrt')) or name in _ATTRIB_DENY_LIST:
>               raise AttributeError(
                    f"{name!r} is not a valid assertion. Use a spec "
                    f"for the mock if {name!r} is meant to be an attribute.")
E               AttributeError: 'called_once_with' is not a valid assertion. Use a spec for the mock if 'called_once_with' is meant to be an attribute.. Did you mean: 'assert_called_once_with'?

name       = 'called_once_with'
self       = <MagicMock name='socket().send' id='140671823548960'>

/usr/lib/python3.12/unittest/mock.py:663: AttributeError
_ TestWebServerPluginWithPacFilePlugin.test_pac_file_served_from_disk[function FindProxyForURL(url, host) { return "PROXY localhost:8899; DIRECT"; }] _

self = <tests.http.web.test_web_server.TestWebServerPluginWithPacFilePlugin object at 0x7ff0b8ab2f00>

    @pytest.mark.asyncio    # type: ignore[misc]
    async def test_pac_file_served_from_disk(self) -> None:
        await self.protocol_handler._run_once()
        self.assertEqual(
            self.protocol_handler.request.state,
            httpParserStates.COMPLETE,
        )
>       self._conn.send.called_once_with(
            build_http_response(
                200,
                reason=b'OK',
                headers={
                    b'Content-Type': b'application/x-ns-proxy-autoconfig',
                },
                body=self.expected_response,
                conn_close=True,
            ),
        )

self       = <tests.http.web.test_web_server.TestWebServerPluginWithPacFilePlugin object at 0x7ff0b8ab2f00>

tests/http/web/test_web_server.py:183: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <MagicMock name='socket().send' id='140671824321312'>
name = 'called_once_with'

    def __getattr__(self, name):
        if name in {'_mock_methods', '_mock_unsafe'}:
            raise AttributeError(name)
        elif self._mock_methods is not None:
            if name not in self._mock_methods or name in _all_magics:
                raise AttributeError("Mock object has no attribute %r" % name)
        elif _is_magic(name):
            raise AttributeError(name)
        if not self._mock_unsafe and (not self._mock_methods or name not in self._mock_methods):
            if name.startswith(('assert', 'assret', 'asert', 'aseert', 'assrt')) or name in _ATTRIB_DENY_LIST:
>               raise AttributeError(
                    f"{name!r} is not a valid assertion. Use a spec "
                    f"for the mock if {name!r} is meant to be an attribute.")
E               AttributeError: 'called_once_with' is not a valid assertion. Use a spec for the mock if 'called_once_with' is meant to be an attribute.. Did you mean: 'assert_called_once_with'?

name       = 'called_once_with'
self       = <MagicMock name='socket().send' id='140671824321312'>

/usr/lib/python3.12/unittest/mock.py:663: AttributeError
-- generated xml file: /tmp/proxy.py/.tox/tmp/test-results/pytest/results.xml --
============================= slowest 10 durations =============================
1.32s call     tests/test_main.py::TestProxyContextManager::test_proxy_context_manager
1.04s call     tests/core/test_event_dispatcher.py::TestEventDispatcher::test_empties_queue
1.04s call     tests/core/test_event_subscriber.py::TestEventSubscriber::test_event_subscriber
1.02s teardown tests/testing/test_embed.py::TestProxyPyEmbedded::test_with_proxy
0.86s teardown tests/http/proxy/test_http2.py::TestHttp2WithProxy::test_http2_via_proxy
0.18s call     tests/http/proxy/test_http2.py::TestHttp2WithProxy::test_http2_via_proxy
0.15s call     tests/common/test_pki.py::TestPki::test_gen_csr
0.12s call     tests/common/test_pki.py::TestPki::test_gen_private_key
0.10s call     tests/testing/test_test_case.py::TestTestCase::test_wait_for_server_raises_timeout_error
0.08s call     tests/plugin/test_http_proxy_plugins.py::TestHttpProxyPluginExamples::test_filter_by_url_regex_plugin[test_filter_by_url_regex_plugin]
=========================== short test summary info ============================
ERROR tests/plugin/test_http_proxy_plugins_with_tls_interception.py::TestHttpProxyPluginExamplesWithTlsInterception::test_modify_post_data_plugin[test_modify_post_data_plugin]
ERROR tests/plugin/test_http_proxy_plugins_with_tls_interception.py::TestHttpProxyPluginExamplesWithTlsInterception::test_man_in_the_middle_plugin[test_man_in_the_middle_plugin]
FAILED tests/http/proxy/test_http_proxy_tls_interception.py::TestHttpProxyTlsInterception::test_e2e
FAILED tests/http/web/test_web_server.py::TestWebServerPluginWithPacFilePlugin::test_pac_file_served_from_disk[/tmp/proxy.py/helper/proxy.pac]
FAILED tests/http/web/test_web_server.py::TestWebServerPluginWithPacFilePlugin::test_pac_file_served_from_disk[function FindProxyForURL(url, host) { return "PROXY localhost:8899; DIRECT"; }]
=================== 3 failed, 217 passed, 2 errors in 20.19s ===================

To Reproduce tox -e py312

Expected behavior Tests passing.

Version information

mgorny commented 1 week ago

FWICS #1347 was supposed to address a part of the problem.

mgorny commented 1 week ago

The other problem is technically solved by doing:

diff --git a/tests/http/web/test_web_server.py b/tests/http/web/test_web_server.py
index 71baac4..e7b2e7a 100644
--- a/tests/http/web/test_web_server.py
+++ b/tests/http/web/test_web_server.py
@@ -180,7 +180,7 @@ class TestWebServerPluginWithPacFilePlugin(Assertions):
             self.protocol_handler.request.state,
             httpParserStates.COMPLETE,
         )
-        self._conn.send.called_once_with(
+        self._conn.send.assert_called_once_with(
             build_http_response(
                 200,
                 reason=b'OK',

but that uncovers that the test didn't work:

============================================================== FAILURES ===============================================================
_________________ TestWebServerPluginWithPacFilePlugin.test_pac_file_served_from_disk[/tmp/proxy.py/helper/proxy.pac] _________________

__wrapped_mock_method__ = <function NonCallableMock.assert_called_once_with at 0x7f53b8319360>
args = (<MagicMock name='socket().send' id='139997494054288'>, b'HTTP/1.1 200 OK\r\nContent-Type: application/x-ns-proxy-auto... 80\r\nConnection: close\r\n\r\nfunction FindProxyForURL(url, host)\n{\n\treturn "PROXY localhost:8899; DIRECT";\n}\n')
kwargs = {}, __tracebackhide__ = True, msg = "Expected 'send' to be called once. Called 0 times."
__mock_self = <MagicMock name='socket().send' id='139997494054288'>

    def assert_wrapper(
        __wrapped_mock_method__: Callable[..., Any], *args: Any, **kwargs: Any
    ) -> None:
        __tracebackhide__ = True
        try:
>           __wrapped_mock_method__(*args, **kwargs)

__mock_self = <MagicMock name='socket().send' id='139997494054288'>
__tracebackhide__ = True
__wrapped_mock_method__ = <function NonCallableMock.assert_called_once_with at 0x7f53b8319360>
args       = (<MagicMock name='socket().send' id='139997494054288'>, b'HTTP/1.1 200 OK\r\nContent-Type: application/x-ns-proxy-auto... 80\r\nConnection: close\r\n\r\nfunction FindProxyForURL(url, host)\n{\n\treturn "PROXY localhost:8899; DIRECT";\n}\n')
kwargs     = {}
msg        = "Expected 'send' to be called once. Called 0 times."

.tox/py310/lib/python3.10/site-packages/pytest_mock/plugin.py:414: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

self = <MagicMock name='socket().send' id='139997494054288'>
args = (b'HTTP/1.1 200 OK\r\nContent-Type: application/x-ns-proxy-autoconfig\r\nContent-Length: 80\r\nConnection: close\r\n\r\nfunction FindProxyForURL(url, host)\n{\n\treturn "PROXY localhost:8899; DIRECT";\n}\n',)
kwargs = {}, msg = "Expected 'send' to be called once. Called 0 times."

    def assert_called_once_with(self, /, *args, **kwargs):
        """assert that the mock was called exactly once and that that call was
        with the specified arguments."""
        if not self.call_count == 1:
            msg = ("Expected '%s' to be called once. Called %s times.%s"
                   % (self._mock_name or 'mock',
                      self.call_count,
                      self._calls_repr()))
>           raise AssertionError(msg)
E           AssertionError: Expected 'send' to be called once. Called 0 times.

args       = (b'HTTP/1.1 200 OK\r\nContent-Type: application/x-ns-proxy-autoconfig\r\nContent-Length: 80\r\nConnection: close\r\n\r\nfunction FindProxyForURL(url, host)\n{\n\treturn "PROXY localhost:8899; DIRECT";\n}\n',)
kwargs     = {}
msg        = "Expected 'send' to be called once. Called 0 times."
self       = <MagicMock name='socket().send' id='139997494054288'>

/usr/lib/python3.10/unittest/mock.py:940: AssertionError

During handling of the above exception, another exception occurred:

self = <tests.http.web.test_web_server.TestWebServerPluginWithPacFilePlugin object at 0x7f53b7705600>

    @pytest.mark.asyncio    # type: ignore[misc]
    async def test_pac_file_served_from_disk(self) -> None:
        await self.protocol_handler._run_once()
        self.assertEqual(
            self.protocol_handler.request.state,
            httpParserStates.COMPLETE,
        )
>       self._conn.send.assert_called_once_with(
            build_http_response(
                200,
                reason=b'OK',
                headers={
                    b'Content-Type': b'application/x-ns-proxy-autoconfig',
                },
                body=self.expected_response,
                conn_close=True,
            ),
        )
E       AssertionError: Expected 'send' to be called once. Called 0 times.

self       = <tests.http.web.test_web_server.TestWebServerPluginWithPacFilePlugin object at 0x7f53b7705600>

tests/http/web/test_web_server.py:183: AssertionError
_ TestWebServerPluginWithPacFilePlugin.test_pac_file_served_from_disk[function FindProxyForURL(url, host) { return "PROXY localhost:8899; DIRECT"; }] _

__wrapped_mock_method__ = <function NonCallableMock.assert_called_once_with at 0x7f53b8319360>
args = (<MagicMock name='socket().send' id='139997494341984'>, b'HTTP/1.1 200 OK\r\nContent-Type: application/x-ns-proxy-auto...Length: 78\r\nConnection: close\r\n\r\nfunction FindProxyForURL(url, host) { return "PROXY localhost:8899; DIRECT"; }')
kwargs = {}, __tracebackhide__ = True, msg = "Expected 'send' to be called once. Called 0 times."
__mock_self = <MagicMock name='socket().send' id='139997494341984'>

    def assert_wrapper(
        __wrapped_mock_method__: Callable[..., Any], *args: Any, **kwargs: Any
    ) -> None:
        __tracebackhide__ = True
        try:
>           __wrapped_mock_method__(*args, **kwargs)

__mock_self = <MagicMock name='socket().send' id='139997494341984'>
__tracebackhide__ = True
__wrapped_mock_method__ = <function NonCallableMock.assert_called_once_with at 0x7f53b8319360>
args       = (<MagicMock name='socket().send' id='139997494341984'>, b'HTTP/1.1 200 OK\r\nContent-Type: application/x-ns-proxy-auto...Length: 78\r\nConnection: close\r\n\r\nfunction FindProxyForURL(url, host) { return "PROXY localhost:8899; DIRECT"; }')
kwargs     = {}
msg        = "Expected 'send' to be called once. Called 0 times."

.tox/py310/lib/python3.10/site-packages/pytest_mock/plugin.py:414: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

self = <MagicMock name='socket().send' id='139997494341984'>
args = (b'HTTP/1.1 200 OK\r\nContent-Type: application/x-ns-proxy-autoconfig\r\nContent-Length: 78\r\nConnection: close\r\n\r\nfunction FindProxyForURL(url, host) { return "PROXY localhost:8899; DIRECT"; }',)
kwargs = {}, msg = "Expected 'send' to be called once. Called 0 times."

    def assert_called_once_with(self, /, *args, **kwargs):
        """assert that the mock was called exactly once and that that call was
        with the specified arguments."""
        if not self.call_count == 1:
            msg = ("Expected '%s' to be called once. Called %s times.%s"
                   % (self._mock_name or 'mock',
                      self.call_count,
                      self._calls_repr()))
>           raise AssertionError(msg)
E           AssertionError: Expected 'send' to be called once. Called 0 times.

args       = (b'HTTP/1.1 200 OK\r\nContent-Type: application/x-ns-proxy-autoconfig\r\nContent-Length: 78\r\nConnection: close\r\n\r\nfunction FindProxyForURL(url, host) { return "PROXY localhost:8899; DIRECT"; }',)
kwargs     = {}
msg        = "Expected 'send' to be called once. Called 0 times."
self       = <MagicMock name='socket().send' id='139997494341984'>

/usr/lib/python3.10/unittest/mock.py:940: AssertionError

During handling of the above exception, another exception occurred:

self = <tests.http.web.test_web_server.TestWebServerPluginWithPacFilePlugin object at 0x7f53b7705ab0>

    @pytest.mark.asyncio    # type: ignore[misc]
    async def test_pac_file_served_from_disk(self) -> None:
        await self.protocol_handler._run_once()
        self.assertEqual(
            self.protocol_handler.request.state,
            httpParserStates.COMPLETE,
        )
>       self._conn.send.assert_called_once_with(
            build_http_response(
                200,
                reason=b'OK',
                headers={
                    b'Content-Type': b'application/x-ns-proxy-autoconfig',
                },
                body=self.expected_response,
                conn_close=True,
            ),
        )
E       AssertionError: Expected 'send' to be called once. Called 0 times.

self       = <tests.http.web.test_web_server.TestWebServerPluginWithPacFilePlugin object at 0x7f53b7705ab0>

tests/http/web/test_web_server.py:183: AssertionError
----------------------------- generated xml file: /tmp/proxy.py/.tox/tmp/test-results/pytest/results.xml ------------------------------
======================================================== slowest 10 durations =========================================================
1.40s call     tests/test_main.py::TestProxyContextManager::test_proxy_context_manager
1.13s call     tests/core/test_event_dispatcher.py::TestEventDispatcher::test_empties_queue
1.12s call     tests/core/test_event_subscriber.py::TestEventSubscriber::test_event_subscriber
1.03s teardown tests/testing/test_embed.py::TestProxyPyEmbedded::test_with_proxy
0.87s teardown tests/http/proxy/test_http2.py::TestHttp2WithProxy::test_http2_via_proxy
0.27s call     tests/http/proxy/test_http2.py::TestHttp2WithProxy::test_http2_via_proxy
0.16s call     tests/common/test_pki.py::TestPki::test_gen_private_key
0.14s call     tests/core/test_event_dispatcher.py::TestEventDispatcher::test_subscribe
0.13s call     tests/core/test_event_queue.py::TestCoreEvent::test_publish
0.13s call     tests/core/test_event_dispatcher.py::TestEventDispatcher::test_unsubscribe
======================================================= short test summary info =======================================================
FAILED tests/http/web/test_web_server.py::TestWebServerPluginWithPacFilePlugin::test_pac_file_served_from_disk[/tmp/proxy.py/helper/proxy.pac]
FAILED tests/http/web/test_web_server.py::TestWebServerPluginWithPacFilePlugin::test_pac_file_served_from_disk[function FindProxyForURL(url, host) { return "PROXY localhost:8899; DIRECT"; }]
=================================================== 2 failed, 220 passed in 11.58s ====================================================