Skip to content

Commit e8d889c

Browse files
committed
ref(test): Add config tests for SSL/proxy for async
GH-4601
1 parent 25c04fc commit e8d889c

File tree

2 files changed

+337
-1
lines changed

2 files changed

+337
-1
lines changed

tests/test_client.py

Lines changed: 316 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,10 @@
2323
from sentry_sdk.spotlight import DEFAULT_SPOTLIGHT_URL
2424
from sentry_sdk.utils import capture_internal_exception
2525
from sentry_sdk.integrations.executing import ExecutingIntegration
26-
from sentry_sdk.transport import Transport
26+
from sentry_sdk.transport import Transport, AsyncHttpTransport
2727
from sentry_sdk.serializer import MAX_DATABAG_BREADTH
2828
from sentry_sdk.consts import DEFAULT_MAX_BREADCRUMBS, DEFAULT_MAX_VALUE_LENGTH
29+
from sentry_sdk._compat import PY38
2930

3031
from typing import TYPE_CHECKING
3132

@@ -1498,3 +1499,317 @@ def test_keep_alive(env_value, arg_value, expected_value):
14981499
)
14991500

15001501
assert transport_cls.options["keep_alive"] is expected_value
1502+
1503+
1504+
@pytest.mark.parametrize(
1505+
"testcase",
1506+
[
1507+
{
1508+
"dsn": "http://[email protected]/123",
1509+
"env_http_proxy": None,
1510+
"env_https_proxy": None,
1511+
"arg_http_proxy": "http://localhost/123",
1512+
"arg_https_proxy": None,
1513+
"expected_proxy_scheme": "http",
1514+
},
1515+
{
1516+
"dsn": "https://[email protected]/123",
1517+
"env_http_proxy": None,
1518+
"env_https_proxy": None,
1519+
"arg_http_proxy": "https://localhost/123",
1520+
"arg_https_proxy": None,
1521+
"expected_proxy_scheme": "https",
1522+
},
1523+
{
1524+
"dsn": "http://[email protected]/123",
1525+
"env_http_proxy": None,
1526+
"env_https_proxy": None,
1527+
"arg_http_proxy": "http://localhost/123",
1528+
"arg_https_proxy": "https://localhost/123",
1529+
"expected_proxy_scheme": "http",
1530+
},
1531+
{
1532+
"dsn": "https://[email protected]/123",
1533+
"env_http_proxy": None,
1534+
"env_https_proxy": None,
1535+
"arg_http_proxy": "http://localhost/123",
1536+
"arg_https_proxy": "https://localhost/123",
1537+
"expected_proxy_scheme": "https",
1538+
},
1539+
{
1540+
"dsn": "https://[email protected]/123",
1541+
"env_http_proxy": None,
1542+
"env_https_proxy": None,
1543+
"arg_http_proxy": "http://localhost/123",
1544+
"arg_https_proxy": None,
1545+
"expected_proxy_scheme": "http",
1546+
},
1547+
{
1548+
"dsn": "http://[email protected]/123",
1549+
"env_http_proxy": None,
1550+
"env_https_proxy": None,
1551+
"arg_http_proxy": None,
1552+
"arg_https_proxy": None,
1553+
"expected_proxy_scheme": None,
1554+
},
1555+
{
1556+
"dsn": "http://[email protected]/123",
1557+
"env_http_proxy": "http://localhost/123",
1558+
"env_https_proxy": None,
1559+
"arg_http_proxy": None,
1560+
"arg_https_proxy": None,
1561+
"expected_proxy_scheme": "http",
1562+
},
1563+
{
1564+
"dsn": "https://[email protected]/123",
1565+
"env_http_proxy": None,
1566+
"env_https_proxy": "https://localhost/123",
1567+
"arg_http_proxy": None,
1568+
"arg_https_proxy": None,
1569+
"expected_proxy_scheme": "https",
1570+
},
1571+
{
1572+
"dsn": "https://[email protected]/123",
1573+
"env_http_proxy": "http://localhost/123",
1574+
"env_https_proxy": None,
1575+
"arg_http_proxy": None,
1576+
"arg_https_proxy": None,
1577+
"expected_proxy_scheme": "http",
1578+
},
1579+
{
1580+
"dsn": "https://[email protected]/123",
1581+
"env_http_proxy": "http://localhost/123",
1582+
"env_https_proxy": "https://localhost/123",
1583+
"arg_http_proxy": "",
1584+
"arg_https_proxy": "",
1585+
"expected_proxy_scheme": None,
1586+
},
1587+
{
1588+
"dsn": "https://[email protected]/123",
1589+
"env_http_proxy": "http://localhost/123",
1590+
"env_https_proxy": "https://localhost/123",
1591+
"arg_http_proxy": None,
1592+
"arg_https_proxy": None,
1593+
"expected_proxy_scheme": "https",
1594+
},
1595+
{
1596+
"dsn": "https://[email protected]/123",
1597+
"env_http_proxy": "http://localhost/123",
1598+
"env_https_proxy": None,
1599+
"arg_http_proxy": None,
1600+
"arg_https_proxy": None,
1601+
"expected_proxy_scheme": "http",
1602+
},
1603+
{
1604+
"dsn": "https://[email protected]/123",
1605+
"env_http_proxy": "http://localhost/123",
1606+
"env_https_proxy": "https://localhost/123",
1607+
"arg_http_proxy": None,
1608+
"arg_https_proxy": "",
1609+
"expected_proxy_scheme": "http",
1610+
},
1611+
{
1612+
"dsn": "https://[email protected]/123",
1613+
"env_http_proxy": "http://localhost/123",
1614+
"env_https_proxy": "https://localhost/123",
1615+
"arg_http_proxy": "",
1616+
"arg_https_proxy": None,
1617+
"expected_proxy_scheme": "https",
1618+
},
1619+
{
1620+
"dsn": "https://[email protected]/123",
1621+
"env_http_proxy": None,
1622+
"env_https_proxy": "https://localhost/123",
1623+
"arg_http_proxy": None,
1624+
"arg_https_proxy": "",
1625+
"expected_proxy_scheme": None,
1626+
},
1627+
{
1628+
"dsn": "http://[email protected]/123",
1629+
"env_http_proxy": "http://localhost/123",
1630+
"env_https_proxy": "https://localhost/123",
1631+
"arg_http_proxy": None,
1632+
"arg_https_proxy": None,
1633+
"expected_proxy_scheme": "http",
1634+
},
1635+
# NO_PROXY testcases
1636+
{
1637+
"dsn": "http://[email protected]/123",
1638+
"env_http_proxy": "http://localhost/123",
1639+
"env_https_proxy": None,
1640+
"env_no_proxy": "sentry.io,example.com",
1641+
"arg_http_proxy": None,
1642+
"arg_https_proxy": None,
1643+
"expected_proxy_scheme": None,
1644+
},
1645+
{
1646+
"dsn": "https://[email protected]/123",
1647+
"env_http_proxy": None,
1648+
"env_https_proxy": "https://localhost/123",
1649+
"env_no_proxy": "example.com,sentry.io",
1650+
"arg_http_proxy": None,
1651+
"arg_https_proxy": None,
1652+
"expected_proxy_scheme": None,
1653+
},
1654+
{
1655+
"dsn": "http://[email protected]/123",
1656+
"env_http_proxy": None,
1657+
"env_https_proxy": None,
1658+
"env_no_proxy": "sentry.io,example.com",
1659+
"arg_http_proxy": "http://localhost/123",
1660+
"arg_https_proxy": None,
1661+
"expected_proxy_scheme": "http",
1662+
},
1663+
{
1664+
"dsn": "https://[email protected]/123",
1665+
"env_http_proxy": None,
1666+
"env_https_proxy": None,
1667+
"env_no_proxy": "sentry.io,example.com",
1668+
"arg_http_proxy": None,
1669+
"arg_https_proxy": "https://localhost/123",
1670+
"expected_proxy_scheme": "https",
1671+
},
1672+
{
1673+
"dsn": "https://[email protected]/123",
1674+
"env_http_proxy": None,
1675+
"env_https_proxy": None,
1676+
"env_no_proxy": "sentry.io,example.com",
1677+
"arg_http_proxy": None,
1678+
"arg_https_proxy": "https://localhost/123",
1679+
"expected_proxy_scheme": "https",
1680+
"arg_proxy_headers": {"Test-Header": "foo-bar"},
1681+
},
1682+
],
1683+
)
1684+
@pytest.mark.asyncio
1685+
@pytest.mark.skipif(not PY38, reason="Async transport requires Python 3.8+")
1686+
async def test_async_proxy(monkeypatch, testcase):
1687+
# These are just the same tests as the sync ones, but they need to be run in an event loop
1688+
# and respect the shutdown behavior of the async transport
1689+
if testcase["env_http_proxy"] is not None:
1690+
monkeypatch.setenv("HTTP_PROXY", testcase["env_http_proxy"])
1691+
if testcase["env_https_proxy"] is not None:
1692+
monkeypatch.setenv("HTTPS_PROXY", testcase["env_https_proxy"])
1693+
if testcase.get("env_no_proxy") is not None:
1694+
monkeypatch.setenv("NO_PROXY", testcase["env_no_proxy"])
1695+
1696+
kwargs = {"_experiments": {"transport_async": True}}
1697+
1698+
if testcase["arg_http_proxy"] is not None:
1699+
kwargs["http_proxy"] = testcase["arg_http_proxy"]
1700+
if testcase["arg_https_proxy"] is not None:
1701+
kwargs["https_proxy"] = testcase["arg_https_proxy"]
1702+
if testcase.get("arg_proxy_headers") is not None:
1703+
kwargs["proxy_headers"] = testcase["arg_proxy_headers"]
1704+
1705+
client = Client(testcase["dsn"], **kwargs)
1706+
assert isinstance(client.transport, AsyncHttpTransport)
1707+
1708+
proxy = getattr(
1709+
client.transport._pool,
1710+
"proxy",
1711+
getattr(client.transport._pool, "_proxy_url", None),
1712+
)
1713+
if testcase["expected_proxy_scheme"] is None:
1714+
assert proxy is None
1715+
else:
1716+
scheme = (
1717+
proxy.scheme.decode("ascii")
1718+
if isinstance(proxy.scheme, bytes)
1719+
else proxy.scheme
1720+
)
1721+
assert scheme == testcase["expected_proxy_scheme"]
1722+
1723+
if testcase.get("arg_proxy_headers") is not None:
1724+
proxy_headers = dict(
1725+
(k.decode("ascii"), v.decode("ascii"))
1726+
for k, v in client.transport._pool._proxy_headers
1727+
)
1728+
assert proxy_headers == testcase["arg_proxy_headers"]
1729+
1730+
await client.close()
1731+
1732+
1733+
@pytest.mark.parametrize(
1734+
"testcase",
1735+
[
1736+
{
1737+
"dsn": "https://[email protected]/123",
1738+
"arg_http_proxy": "http://localhost/123",
1739+
"arg_https_proxy": None,
1740+
"should_be_socks_proxy": False,
1741+
},
1742+
{
1743+
"dsn": "https://[email protected]/123",
1744+
"arg_http_proxy": "socks4a://localhost/123",
1745+
"arg_https_proxy": None,
1746+
"should_be_socks_proxy": True,
1747+
},
1748+
{
1749+
"dsn": "https://[email protected]/123",
1750+
"arg_http_proxy": "socks4://localhost/123",
1751+
"arg_https_proxy": None,
1752+
"should_be_socks_proxy": True,
1753+
},
1754+
{
1755+
"dsn": "https://[email protected]/123",
1756+
"arg_http_proxy": "socks5h://localhost/123",
1757+
"arg_https_proxy": None,
1758+
"should_be_socks_proxy": True,
1759+
},
1760+
{
1761+
"dsn": "https://[email protected]/123",
1762+
"arg_http_proxy": "socks5://localhost/123",
1763+
"arg_https_proxy": None,
1764+
"should_be_socks_proxy": True,
1765+
},
1766+
{
1767+
"dsn": "https://[email protected]/123",
1768+
"arg_http_proxy": None,
1769+
"arg_https_proxy": "socks4a://localhost/123",
1770+
"should_be_socks_proxy": True,
1771+
},
1772+
{
1773+
"dsn": "https://[email protected]/123",
1774+
"arg_http_proxy": None,
1775+
"arg_https_proxy": "socks4://localhost/123",
1776+
"should_be_socks_proxy": True,
1777+
},
1778+
{
1779+
"dsn": "https://[email protected]/123",
1780+
"arg_http_proxy": None,
1781+
"arg_https_proxy": "socks5h://localhost/123",
1782+
"should_be_socks_proxy": True,
1783+
},
1784+
{
1785+
"dsn": "https://[email protected]/123",
1786+
"arg_http_proxy": None,
1787+
"arg_https_proxy": "socks5://localhost/123",
1788+
"should_be_socks_proxy": True,
1789+
},
1790+
],
1791+
)
1792+
@pytest.mark.asyncio
1793+
@pytest.mark.skipif(not PY38, reason="Async transport requires Python 3.8+")
1794+
async def test_async_socks_proxy(testcase):
1795+
# These are just the same tests as the sync ones, but they need to be run in an event loop
1796+
# and respect the shutdown behavior of the async transport
1797+
1798+
kwargs = {"_experiments": {"transport_async": True}}
1799+
1800+
if testcase["arg_http_proxy"] is not None:
1801+
kwargs["http_proxy"] = testcase["arg_http_proxy"]
1802+
if testcase["arg_https_proxy"] is not None:
1803+
kwargs["https_proxy"] = testcase["arg_https_proxy"]
1804+
1805+
client = Client(testcase["dsn"], **kwargs)
1806+
assert isinstance(client.transport, AsyncHttpTransport)
1807+
1808+
assert ("socks" in str(type(client.transport._pool)).lower()) == testcase[
1809+
"should_be_socks_proxy"
1810+
], (
1811+
f"Expected {kwargs} to result in SOCKS == {testcase['should_be_socks_proxy']}"
1812+
f"but got {str(type(client.transport._pool))}"
1813+
)
1814+
1815+
await client.close()

tests/test_transport.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -876,3 +876,24 @@ async def send_message(i):
876876
# New request should be dropped due to rate limiting
877877
assert len(capturing_server.captured) == 0
878878
await client.close(timeout=2.0)
879+
880+
881+
@pytest.mark.asyncio
882+
@pytest.mark.skipif(not PY38, reason="Async transport requires Python 3.8+")
883+
async def test_async_two_way_ssl_authentication():
884+
current_dir = os.path.dirname(__file__)
885+
cert_file = f"{current_dir}/test.pem"
886+
key_file = f"{current_dir}/test.key"
887+
888+
client = Client(
889+
"https://[email protected]/123",
890+
cert_file=cert_file,
891+
key_file=key_file,
892+
_experiments={"transport_async": True},
893+
)
894+
assert isinstance(client.transport, AsyncHttpTransport)
895+
896+
options = client.transport._get_pool_options()
897+
assert options["ssl_context"] is not None
898+
899+
await client.close()

0 commit comments

Comments
 (0)