Skip to content

Commit 3ba8d3a

Browse files
committed
add tests and sure passing tests
1 parent 8e00a4d commit 3ba8d3a

File tree

4 files changed

+355
-2
lines changed

4 files changed

+355
-2
lines changed

ipinfo/handler_resproxy_async.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ async def getDetails(self, ip_address=None, timeout=None):
138138
details = await resp.json()
139139

140140
self.cache[cache_key(ip_address)] = details
141-
return Details
141+
return Details(details)
142142

143143
async def getBatchDetails(
144144
self,

ipinfo/handler_utils.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
PLUS_API_URL = "https://api.ipinfo.io/lookup"
2323

2424
# Base URL for the IPinfo Residential Proxy API
25-
RESPROXY_API_URL = "https://api.ipinfo.io/resproxy"
25+
RESPROXY_API_URL = "https://ipinfo.io/resproxy"
2626

2727
# Base URL to get country flag image link.
2828
# "PK" -> "https://cdn.ipinfo.io/static/images/countries-flags/PK.svg"
Lines changed: 187 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
1+
import os
2+
3+
import pytest
4+
5+
from ipinfo import handler_utils
6+
from ipinfo.cache.default import DefaultCache
7+
from ipinfo.details import Details
8+
from ipinfo.handler_resproxy_async import AsyncHandlerResProxy
9+
10+
11+
@pytest.mark.asyncio
12+
async def test_init():
13+
token = "mytesttoken"
14+
handler = AsyncHandlerResProxy(token)
15+
assert handler.access_token == token
16+
assert isinstance(handler.cache, DefaultCache)
17+
await handler.deinit()
18+
19+
20+
@pytest.mark.asyncio
21+
async def test_headers():
22+
token = "mytesttoken"
23+
handler = AsyncHandlerResProxy(token, headers={"custom_field": "yes"})
24+
headers = handler_utils.get_headers(token, handler.headers)
25+
await handler.deinit()
26+
27+
assert "user-agent" in headers
28+
assert "accept" in headers
29+
assert "authorization" in headers
30+
assert "custom_field" in headers
31+
32+
33+
@pytest.mark.skipif(
34+
"IPINFO_TOKEN" not in os.environ,
35+
reason="Can't call ResProxy API without token",
36+
)
37+
@pytest.mark.asyncio
38+
async def test_get_details():
39+
"""Test basic ResProxy API lookup"""
40+
token = os.environ.get("IPINFO_TOKEN", "")
41+
handler = AsyncHandlerResProxy(token)
42+
details = await handler.getDetails("139.5.0.122")
43+
44+
# Should return Details object
45+
assert isinstance(details, Details)
46+
assert details.ip == "139.5.0.122"
47+
48+
# Check ResProxy-specific fields
49+
assert hasattr(details, "last_seen")
50+
assert hasattr(details, "percent_days_seen")
51+
assert hasattr(details, "service")
52+
53+
await handler.deinit()
54+
55+
56+
#############
57+
# BOGON TESTS
58+
#############
59+
60+
61+
@pytest.mark.skipif(
62+
"IPINFO_TOKEN" not in os.environ,
63+
reason="Can't call ResProxy API without token",
64+
)
65+
@pytest.mark.asyncio
66+
async def test_bogon_details():
67+
token = os.environ.get("IPINFO_TOKEN", "")
68+
handler = AsyncHandlerResProxy(token)
69+
details = await handler.getDetails("127.0.0.1")
70+
assert isinstance(details, Details)
71+
assert details.all == {"bogon": True, "ip": "127.0.0.1"}
72+
await handler.deinit()
73+
74+
75+
#####################
76+
# BATCH TESTS
77+
#####################
78+
79+
80+
@pytest.mark.skipif(
81+
"IPINFO_TOKEN" not in os.environ,
82+
reason="Can't call ResProxy API without token",
83+
)
84+
@pytest.mark.asyncio
85+
async def test_batch_ips():
86+
"""Test batch request with IPs"""
87+
token = os.environ.get("IPINFO_TOKEN", "")
88+
handler = AsyncHandlerResProxy(token)
89+
results = await handler.getBatchDetails(["139.5.0.122", "45.95.168.1"])
90+
91+
assert len(results) == 2
92+
assert "139.5.0.122" in results
93+
assert "45.95.168.1" in results
94+
95+
# Both should be Details objects
96+
assert isinstance(results["139.5.0.122"], Details)
97+
assert isinstance(results["45.95.168.1"], Details)
98+
99+
# Check ResProxy-specific fields
100+
assert hasattr(results["139.5.0.122"], "last_seen")
101+
assert hasattr(results["139.5.0.122"], "percent_days_seen")
102+
assert hasattr(results["139.5.0.122"], "service")
103+
104+
await handler.deinit()
105+
106+
107+
@pytest.mark.skipif(
108+
"IPINFO_TOKEN" not in os.environ,
109+
reason="Can't call ResProxy API without token",
110+
)
111+
@pytest.mark.asyncio
112+
async def test_batch_with_bogon():
113+
"""Test batch including bogon IPs"""
114+
token = os.environ.get("IPINFO_TOKEN", "")
115+
handler = AsyncHandlerResProxy(token)
116+
results = await handler.getBatchDetails(
117+
[
118+
"139.5.0.122",
119+
"127.0.0.1", # Bogon
120+
"45.95.168.1",
121+
]
122+
)
123+
124+
assert len(results) == 3
125+
126+
# Normal IPs should be Details
127+
assert isinstance(results["139.5.0.122"], Details)
128+
assert isinstance(results["45.95.168.1"], Details)
129+
130+
# Bogon should also be Details with bogon flag
131+
assert isinstance(results["127.0.0.1"], Details)
132+
assert results["127.0.0.1"].bogon == True
133+
134+
await handler.deinit()
135+
136+
137+
#####################
138+
# CACHING TESTS
139+
#####################
140+
141+
142+
@pytest.mark.skipif(
143+
"IPINFO_TOKEN" not in os.environ,
144+
reason="Can't call ResProxy API without token",
145+
)
146+
@pytest.mark.asyncio
147+
async def test_caching():
148+
"""Test that results are properly cached"""
149+
token = os.environ.get("IPINFO_TOKEN", "")
150+
handler = AsyncHandlerResProxy(token)
151+
152+
# First request - should hit API
153+
details1 = await handler.getDetails("139.5.0.122")
154+
assert isinstance(details1, Details)
155+
156+
# Second request - should come from cache
157+
details2 = await handler.getDetails("139.5.0.122")
158+
assert isinstance(details2, Details)
159+
assert details2.ip == details1.ip
160+
161+
# Verify cache key exists
162+
cache_key_val = handler_utils.cache_key("139.5.0.122")
163+
assert cache_key_val in handler.cache
164+
165+
await handler.deinit()
166+
167+
168+
@pytest.mark.skipif(
169+
"IPINFO_TOKEN" not in os.environ,
170+
reason="Can't call ResProxy API without token",
171+
)
172+
@pytest.mark.asyncio
173+
async def test_batch_caching():
174+
"""Test that batch results are properly cached"""
175+
token = os.environ.get("IPINFO_TOKEN", "")
176+
handler = AsyncHandlerResProxy(token)
177+
178+
# First batch request
179+
results1 = await handler.getBatchDetails(["139.5.0.122", "45.95.168.1"])
180+
assert len(results1) == 2
181+
182+
# Second batch with same IPs (should come from cache)
183+
results2 = await handler.getBatchDetails(["139.5.0.122", "45.95.168.1"])
184+
assert len(results2) == 2
185+
assert results2["139.5.0.122"].ip == results1["139.5.0.122"].ip
186+
187+
await handler.deinit()

tests/handler_resproxy_test.py

Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
import os
2+
3+
import pytest
4+
5+
from ipinfo import handler_utils
6+
from ipinfo.cache.default import DefaultCache
7+
from ipinfo.details import Details
8+
from ipinfo.handler_resproxy import HandlerResProxy
9+
10+
11+
def test_init():
12+
token = "mytesttoken"
13+
handler = HandlerResProxy(token)
14+
assert handler.access_token == token
15+
assert isinstance(handler.cache, DefaultCache)
16+
17+
18+
def test_headers():
19+
token = "mytesttoken"
20+
handler = HandlerResProxy(token, headers={"custom_field": "yes"})
21+
headers = handler_utils.get_headers(token, handler.headers)
22+
23+
assert "user-agent" in headers
24+
assert "accept" in headers
25+
assert "authorization" in headers
26+
assert "custom_field" in headers
27+
28+
29+
@pytest.mark.skipif(
30+
"IPINFO_TOKEN" not in os.environ,
31+
reason="Can't call ResProxy API without token",
32+
)
33+
def test_get_details():
34+
"""Test basic ResProxy API lookup"""
35+
token = os.environ.get("IPINFO_TOKEN", "")
36+
handler = HandlerResProxy(token)
37+
details = handler.getDetails("139.5.0.122")
38+
39+
# Should return Details object
40+
assert isinstance(details, Details)
41+
assert details.ip == "139.5.0.122"
42+
43+
# Check ResProxy-specific fields
44+
assert hasattr(details, "last_seen")
45+
assert hasattr(details, "percent_days_seen")
46+
assert hasattr(details, "service")
47+
48+
49+
#############
50+
# BOGON TESTS
51+
#############
52+
53+
54+
@pytest.mark.skipif(
55+
"IPINFO_TOKEN" not in os.environ,
56+
reason="Can't call ResProxy API without token",
57+
)
58+
def test_bogon_details():
59+
token = os.environ.get("IPINFO_TOKEN", "")
60+
handler = HandlerResProxy(token)
61+
details = handler.getDetails("127.0.0.1")
62+
assert isinstance(details, Details)
63+
assert details.all == {"bogon": True, "ip": "127.0.0.1"}
64+
65+
66+
#####################
67+
# BATCH TESTS
68+
#####################
69+
70+
71+
@pytest.mark.skipif(
72+
"IPINFO_TOKEN" not in os.environ,
73+
reason="Can't call ResProxy API without token",
74+
)
75+
def test_batch_ips():
76+
"""Test batch request with IPs"""
77+
token = os.environ.get("IPINFO_TOKEN", "")
78+
handler = HandlerResProxy(token)
79+
results = handler.getBatchDetails(["139.5.0.122", "45.95.168.1"])
80+
81+
assert len(results) == 2
82+
assert "139.5.0.122" in results
83+
assert "45.95.168.1" in results
84+
85+
# Both should be Details objects
86+
assert isinstance(results["139.5.0.122"], Details)
87+
assert isinstance(results["45.95.168.1"], Details)
88+
89+
# Check ResProxy-specific fields
90+
assert hasattr(results["139.5.0.122"], "last_seen")
91+
assert hasattr(results["139.5.0.122"], "percent_days_seen")
92+
assert hasattr(results["139.5.0.122"], "service")
93+
94+
95+
@pytest.mark.skipif(
96+
"IPINFO_TOKEN" not in os.environ,
97+
reason="Can't call ResProxy API without token",
98+
)
99+
def test_batch_with_bogon():
100+
"""Test batch including bogon IPs"""
101+
token = os.environ.get("IPINFO_TOKEN", "")
102+
handler = HandlerResProxy(token)
103+
results = handler.getBatchDetails(
104+
[
105+
"139.5.0.122",
106+
"127.0.0.1", # Bogon
107+
"45.95.168.1",
108+
]
109+
)
110+
111+
assert len(results) == 3
112+
113+
# Normal IPs should be Details
114+
assert isinstance(results["139.5.0.122"], Details)
115+
assert isinstance(results["45.95.168.1"], Details)
116+
117+
# Bogon should also be Details with bogon flag
118+
assert isinstance(results["127.0.0.1"], Details)
119+
assert results["127.0.0.1"].bogon == True
120+
121+
122+
#####################
123+
# CACHING TESTS
124+
#####################
125+
126+
127+
@pytest.mark.skipif(
128+
"IPINFO_TOKEN" not in os.environ,
129+
reason="Can't call ResProxy API without token",
130+
)
131+
def test_caching():
132+
"""Test that results are properly cached"""
133+
token = os.environ.get("IPINFO_TOKEN", "")
134+
handler = HandlerResProxy(token)
135+
136+
# First request - should hit API
137+
details1 = handler.getDetails("139.5.0.122")
138+
assert isinstance(details1, Details)
139+
140+
# Second request - should come from cache
141+
details2 = handler.getDetails("139.5.0.122")
142+
assert isinstance(details2, Details)
143+
assert details2.ip == details1.ip
144+
145+
# Verify cache key exists
146+
cache_key_val = handler_utils.cache_key("139.5.0.122")
147+
assert cache_key_val in handler.cache
148+
149+
150+
@pytest.mark.skipif(
151+
"IPINFO_TOKEN" not in os.environ,
152+
reason="Can't call ResProxy API without token",
153+
)
154+
def test_batch_caching():
155+
"""Test that batch results are properly cached"""
156+
token = os.environ.get("IPINFO_TOKEN", "")
157+
handler = HandlerResProxy(token)
158+
159+
# First batch request
160+
results1 = handler.getBatchDetails(["139.5.0.122", "45.95.168.1"])
161+
assert len(results1) == 2
162+
163+
# Second batch with same IPs (should come from cache)
164+
results2 = handler.getBatchDetails(["139.5.0.122", "45.95.168.1"])
165+
assert len(results2) == 2
166+
assert results2["139.5.0.122"].ip == results1["139.5.0.122"].ip

0 commit comments

Comments
 (0)