Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# AGENTS.md

## Pull Requests

PRs MUST be opened against **customerio/cdp-analytics-python** (branch: `main`).

Never open PRs against segmentio/analytics-python — this repo is a fork and we do not contribute upstream.

When creating a PR, always use: `gh pr create --repo customerio/cdp-analytics-python --base main`

## Tests

Run tests with: `make test`
1 change: 1 addition & 0 deletions CLAUDE.md
7 changes: 3 additions & 4 deletions customerio/analytics/request.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,14 +39,13 @@ def post(write_key, host=None, gzip=False, timeout=15, proxies=None, **kwargs):
"data": data,
"auth": auth,
"headers": headers,
"timeout": 15,
"timeout": timeout,
}

if proxies:
if proxies is not None:
kwargs['proxies'] = proxies

res = _session.post(url, data=data, auth=auth,
headers=headers, timeout=timeout)
res = _session.post(url, **kwargs)

if res.status_code == 200:
log.debug('data uploaded successfully')
Expand Down
32 changes: 27 additions & 5 deletions customerio/analytics/test/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -318,20 +318,32 @@ def test_gzip(self):

def test_user_defined_upload_size(self):
client = Client('testsecret', on_error=self.fail,
upload_size=10, upload_interval=3)
upload_size=10, upload_interval=0.3)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Non-blocking. Is the upload_interval=30.3 change intentional? Looks unrelated to the proxy/timeout fix — if it is a test speed improvement, a comment would make it clear.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will add comment, thanks.


def mock_post_fn(*args, **kwargs):
self.assertEqual(len(kwargs['batch']), 10)

# the post function should be called 2 times, with a batch size of 10
# each time.
# each time. 0.3s upload_interval ensures both batches are sent
# during 1 second sleep.
with mock.patch('customerio.analytics.consumer.post', side_effect=mock_post_fn) \
as mock_post:
for _ in range(20):
client.identify('userId', {'trait': 'value'})
time.sleep(1)
self.assertEqual(mock_post.call_count, 2)

def test_user_defined_upload_interval(self):
upload_interval = 0.3
client = Client('testsecret', on_error=self.fail,
upload_size=100, upload_interval=upload_interval)

with mock.patch('customerio.analytics.consumer.post') as mock_post:
for _ in range(3):
client.identify('userId', {'trait': 'value'})
time.sleep(upload_interval * 1.1)
self.assertEqual(mock_post.call_count, 3)

def test_user_defined_timeout(self):
client = Client('testsecret', timeout=10)
for consumer in client.consumers:
Expand All @@ -343,6 +355,16 @@ def test_default_timeout_15(self):
self.assertEqual(consumer.timeout, 15)

def test_proxies(self):
client = Client('testsecret', proxies='203.243.63.16:80')
success, msg = client.identify('userId', {'trait': 'value'})
self.assertTrue(success)
proxies = {
'https': 'http://proxy.example.com:8080',
'http': 'http://proxy.example.com:8080',
}
client = Client('testsecret', sync_mode=True, proxies=proxies)
mock_response = mock.Mock()
mock_response.status_code = 200
with mock.patch('customerio.analytics.request._session.post',
return_value=mock_response) as mock_post:
client.identify('userId', {'trait': 'value'})
mock_post.assert_called_once()
_, call_kwargs = mock_post.call_args
self.assertEqual(call_kwargs['proxies'], proxies)
14 changes: 6 additions & 8 deletions customerio/analytics/test/consumer.py
Original file line number Diff line number Diff line change
Expand Up @@ -198,12 +198,10 @@ def mock_post_fn(_, data, **kwargs):
q.join()
self.assertEqual(mock_post.call_count, 2)

@classmethod
def test_proxies(cls):
consumer = Consumer(None, 'testsecret', proxies='203.243.63.16:80')
track = {
'type': 'track',
'event': 'python event',
'userId': 'userId'
def test_proxies(self):
proxies = {
'http': 'http://192.0.2.1:80',
'https': 'http://192.0.2.1:80',
}
consumer.request([track])
consumer = Consumer(None, 'testsecret', proxies=proxies)
self.assertEqual(consumer.proxies, proxies)
40 changes: 32 additions & 8 deletions customerio/analytics/test/request.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from datetime import datetime, date
import unittest
import unittest.mock as mock
import json
import requests

Expand Down Expand Up @@ -52,11 +53,34 @@ def test_should_timeout(self):
'type': 'track'
}], timeout=0.0001)

def test_proxies(self):
res = post('testsecret', batch=[{
'userId': 'userId',
'event': 'python event',
'type': 'track',
'proxies': '203.243.63.16:80'
}])
self.assertEqual(res.status_code, 200)
def test_proxies_passed_to_session(self):
proxies = {
'https': 'http://proxy.example.com:8080',
'http': 'http://proxy.example.com:8080',
}
mock_response = mock.Mock()
mock_response.status_code = 200
with mock.patch('customerio.analytics.request._session.post',
return_value=mock_response) as mock_post:
post('testsecret', proxies=proxies, batch=[{
'userId': 'userId',
'event': 'python event',
'type': 'track',
}])
mock_post.assert_called_once()
_, call_kwargs = mock_post.call_args
self.assertEqual(call_kwargs['proxies'], proxies)

def test_no_proxies_by_default(self):
mock_response = mock.Mock()
mock_response.status_code = 200
with mock.patch('customerio.analytics.request._session.post',
return_value=mock_response) as mock_post:
post('testsecret', batch=[{
'userId': 'userId',
'event': 'python event',
'type': 'track',
}])
mock_post.assert_called_once()
_, call_kwargs = mock_post.call_args
self.assertNotIn('proxies', call_kwargs)