Skip to content

Commit 4da3a6d

Browse files
authored
Merge pull request #154 from splitio/feature/doNotSendIpFlag
added flag to enable/disable sending ip in headers
2 parents 1ae99bf + 0f4bf5f commit 4da3a6d

File tree

8 files changed

+230
-77
lines changed

8 files changed

+230
-77
lines changed

CHANGES.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
8.1.3 (Oct XX, 2019)
22
- Added logic to fetch multiple splits at once on get_treatments/get_treatments_with_config.
3+
- Added flag `ipAddressesEnabled` into config to enable/disable sending machineName and machineIp when data is posted in headers.
34

45
8.1.2 (Jul 19, 2019)
56
- Validated TLS support for redis connections

splitio/api/__init__.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
"""Split API module."""
22

3+
34
class APIException(Exception):
45
"""Exception to raise when an API call fails."""
56

@@ -28,4 +29,6 @@ def headers_from_metadata(sdk_metadata):
2829
'SplitSDKVersion': sdk_metadata.sdk_version,
2930
'SplitSDKMachineIP': sdk_metadata.instance_ip,
3031
'SplitSDKMachineName': sdk_metadata.instance_name
32+
} if sdk_metadata.instance_ip != 'NA' and sdk_metadata.instance_ip != 'unknown' else {
33+
'SplitSDKVersion': sdk_metadata.sdk_version,
3134
}

splitio/client/config.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
'eventsBulkSize': 5000,
1717
'eventsQueueSize': 10000,
1818
'labelsEnabled': True,
19+
'ipAddressesEnabled': True,
1920
'impressionListener': None,
2021
'redisHost': 'localhost',
2122
'redisPort': 6379,

splitio/client/util.py

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,16 @@ def _get_hostname(ip_address):
2828
return 'unknown' if ip_address == 'unknown' else 'ip-' + ip_address.replace('.', '-')
2929

3030

31+
def _get_hostname_and_ip(config):
32+
if config.get('ipAddressesEnabled') is False:
33+
return 'NA', 'NA'
34+
ip_from_config = config.get('machineIp')
35+
machine_from_config = config.get('machineName')
36+
ip_address = ip_from_config if ip_from_config is not None else _get_ip()
37+
hostname = machine_from_config if machine_from_config is not None else _get_hostname(ip_address)
38+
return ip_address, hostname
39+
40+
3141
def get_metadata(config):
3242
"""
3343
Gather SDK metadata and return a tuple with such info.
@@ -39,10 +49,7 @@ def get_metadata(config):
3949
:rtype: SdkMetadata
4050
"""
4151
version = 'python-%s' % __version__
42-
ip_from_config = config.get('machineIp')
43-
machine_from_config = config.get('machineName')
44-
ip_address = ip_from_config if ip_from_config is not None else _get_ip()
45-
hostname = machine_from_config if machine_from_config is not None else _get_hostname(ip_address)
52+
ip_address, hostname = _get_hostname_and_ip(config)
4653
return SdkMetadata(version, hostname, ip_address)
4754

4855

tests/api/test_events.py

Lines changed: 45 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -3,24 +3,35 @@
33
import pytest
44
from splitio.api import events, client, APIException
55
from splitio.models.events import Event
6-
from splitio.client.util import SdkMetadata
6+
from splitio.client.util import get_metadata
7+
from splitio.client.config import DEFAULT_CONFIG
8+
from splitio.version import __version__
79

810

911
class EventsAPITests(object):
1012
"""Impressions API test cases."""
13+
events = [
14+
Event('k1', 'user', 'purchase', 12.50, 123456, None),
15+
Event('k2', 'user', 'purchase', 12.50, 123456, None),
16+
Event('k3', 'user', 'purchase', None, 123456, {"test": 1234}),
17+
Event('k4', 'user', 'purchase', None, 123456, None)
18+
]
19+
eventsExpected = [
20+
{'key': 'k1', 'trafficTypeName': 'user', 'eventTypeId': 'purchase', 'value': 12.50, 'timestamp': 123456, 'properties': None},
21+
{'key': 'k2', 'trafficTypeName': 'user', 'eventTypeId': 'purchase', 'value': 12.50, 'timestamp': 123456, 'properties': None},
22+
{'key': 'k3', 'trafficTypeName': 'user', 'eventTypeId': 'purchase', 'value': None, 'timestamp': 123456, 'properties': {"test": 1234}},
23+
{'key': 'k4', 'trafficTypeName': 'user', 'eventTypeId': 'purchase', 'value': None, 'timestamp': 123456, 'properties': None},
24+
]
1125

1226
def test_post_events(self, mocker):
1327
"""Test impressions posting API call."""
1428
httpclient = mocker.Mock(spec=client.HttpClient)
1529
httpclient.post.return_value = client.HttpResponse(200, '')
16-
sdk_metadata = SdkMetadata('python-1.2.3', 'some_machine_name', '123.123.123.123')
30+
cfg = DEFAULT_CONFIG.copy()
31+
cfg.update({'ipAddressesEnabled': True, 'machineName': 'some_machine_name', 'machineIp': '123.123.123.123'})
32+
sdk_metadata = get_metadata(cfg)
1733
events_api = events.EventsAPI(httpclient, 'some_api_key', sdk_metadata)
18-
response = events_api.flush_events([
19-
Event('k1', 'user', 'purchase', 12.50, 123456, None),
20-
Event('k2', 'user', 'purchase', 12.50, 123456, None),
21-
Event('k3', 'user', 'purchase', None, 123456, {"test": 1234}),
22-
Event('k4', 'user', 'purchase', None, 123456, None)
23-
])
34+
response = events_api.flush_events(self.events)
2435

2536
call_made = httpclient.post.mock_calls[0]
2637

@@ -29,29 +40,42 @@ def test_post_events(self, mocker):
2940

3041
# validate key-value args (headers)
3142
assert call_made[2]['extra_headers'] == {
32-
'SplitSDKVersion': 'python-1.2.3',
43+
'SplitSDKVersion': 'python-%s' % __version__,
3344
'SplitSDKMachineIP': '123.123.123.123',
3445
'SplitSDKMachineName': 'some_machine_name'
3546
}
3647

3748
# validate key-value args (body)
38-
assert call_made[2]['body'] == [
39-
{'key': 'k1', 'trafficTypeName': 'user', 'eventTypeId': 'purchase', 'value': 12.50, 'timestamp': 123456, 'properties': None},
40-
{'key': 'k2', 'trafficTypeName': 'user', 'eventTypeId': 'purchase', 'value': 12.50, 'timestamp': 123456, 'properties': None},
41-
{'key': 'k3', 'trafficTypeName': 'user', 'eventTypeId': 'purchase', 'value': None, 'timestamp': 123456, 'properties': {"test": 1234}},
42-
{'key': 'k4', 'trafficTypeName': 'user', 'eventTypeId': 'purchase', 'value': None, 'timestamp': 123456, 'properties': None},
43-
]
49+
assert call_made[2]['body'] == self.eventsExpected
4450

4551
httpclient.reset_mock()
4652
def raise_exception(*args, **kwargs):
4753
raise client.HttpClientException('some_message')
4854
httpclient.post.side_effect = raise_exception
4955
with pytest.raises(APIException) as exc_info:
50-
response = events_api.flush_events([
51-
Event('k1', 'user', 'purchase', 12.50, 123456, None),
52-
Event('k2', 'user', 'purchase', 12.50, 123456, None),
53-
Event('k3', 'user', 'purchase', None, 123456, None),
54-
Event('k4', 'user', 'purchase', None, 123456, None)
55-
])
56+
response = events_api.flush_events(self.events)
5657
assert exc_info.type == APIException
5758
assert exc_info.value.message == 'some_message'
59+
60+
def test_post_events_ip_address_disabled(self, mocker):
61+
"""Test impressions posting API call."""
62+
httpclient = mocker.Mock(spec=client.HttpClient)
63+
httpclient.post.return_value = client.HttpResponse(200, '')
64+
cfg = DEFAULT_CONFIG.copy()
65+
cfg.update({'ipAddressesEnabled': False})
66+
sdk_metadata = get_metadata(cfg)
67+
events_api = events.EventsAPI(httpclient, 'some_api_key', sdk_metadata)
68+
response = events_api.flush_events(self.events)
69+
70+
call_made = httpclient.post.mock_calls[0]
71+
72+
# validate positional arguments
73+
assert call_made[1] == ('events', '/events/bulk', 'some_api_key')
74+
75+
# validate key-value args (headers)
76+
assert call_made[2]['extra_headers'] == {
77+
'SplitSDKVersion': 'python-%s' % __version__,
78+
}
79+
80+
# validate key-value args (body)
81+
assert call_made[2]['body'] == self.eventsExpected

tests/api/test_impressions_api.py

Lines changed: 51 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -3,22 +3,40 @@
33
import pytest
44
from splitio.api import impressions, client, APIException
55
from splitio.models.impressions import Impression
6-
from splitio.client.util import SdkMetadata
6+
from splitio.client.util import get_metadata
7+
from splitio.client.config import DEFAULT_CONFIG
8+
from splitio.version import __version__
9+
710

811
class ImpressionsAPITests(object):
912
"""Impressions API test cases."""
13+
impressions = [
14+
Impression('k1', 'f1', 'on', 'l1', 123456, 'b1', 321654),
15+
Impression('k2', 'f2', 'off', 'l1', 123456, 'b1', 321654),
16+
Impression('k3', 'f1', 'on', 'l1', 123456, 'b1', 321654)
17+
]
18+
expectedImpressions = [{
19+
'testName': 'f1',
20+
'keyImpressions': [
21+
{'keyName': 'k1', 'bucketingKey': 'b1', 'treatment': 'on', 'label': 'l1', 'time': 321654, 'changeNumber': 123456},
22+
{'keyName': 'k3', 'bucketingKey': 'b1', 'treatment': 'on', 'label': 'l1', 'time': 321654, 'changeNumber': 123456},
23+
],
24+
}, {
25+
'testName': 'f2',
26+
'keyImpressions': [
27+
{'keyName': 'k2', 'bucketingKey': 'b1', 'treatment': 'off', 'label': 'l1', 'time': 321654, 'changeNumber': 123456},
28+
]
29+
}]
1030

1131
def test_post_impressions(self, mocker):
1232
"""Test impressions posting API call."""
1333
httpclient = mocker.Mock(spec=client.HttpClient)
1434
httpclient.post.return_value = client.HttpResponse(200, '')
15-
sdk_metadata = SdkMetadata('python-1.2.3', 'some_machine_name', '123.123.123.123')
35+
cfg = DEFAULT_CONFIG.copy()
36+
cfg.update({'ipAddressesEnabled': True, 'machineName': 'some_machine_name', 'machineIp': '123.123.123.123'})
37+
sdk_metadata = get_metadata(cfg)
1638
impressions_api = impressions.ImpressionsAPI(httpclient, 'some_api_key', sdk_metadata)
17-
response = impressions_api.flush_impressions([
18-
Impression('k1', 'f1', 'on', 'l1', 123456, 'b1', 321654),
19-
Impression('k2', 'f2', 'off', 'l1', 123456, 'b1', 321654),
20-
Impression('k3', 'f1', 'on', 'l1', 123456, 'b1', 321654),
21-
])
39+
response = impressions_api.flush_impressions(self.impressions)
2240

2341
call_made = httpclient.post.mock_calls[0]
2442

@@ -27,37 +45,42 @@ def test_post_impressions(self, mocker):
2745

2846
# validate key-value args (headers)
2947
assert call_made[2]['extra_headers'] == {
30-
'SplitSDKVersion': 'python-1.2.3',
48+
'SplitSDKVersion': 'python-%s' % __version__,
3149
'SplitSDKMachineIP': '123.123.123.123',
3250
'SplitSDKMachineName': 'some_machine_name'
3351
}
3452

3553
# validate key-value args (body)
36-
assert call_made[2]['body'] == [
37-
{
38-
'testName': 'f1',
39-
'keyImpressions': [
40-
{'keyName': 'k1', 'bucketingKey': 'b1', 'treatment': 'on', 'label': 'l1', 'time': 321654, 'changeNumber': 123456},
41-
{'keyName': 'k3', 'bucketingKey': 'b1', 'treatment': 'on', 'label': 'l1', 'time': 321654, 'changeNumber': 123456},
42-
],
43-
},
44-
{
45-
'testName': 'f2',
46-
'keyImpressions': [
47-
{'keyName': 'k2', 'bucketingKey': 'b1', 'treatment': 'off', 'label': 'l1', 'time': 321654, 'changeNumber': 123456},
48-
]
49-
}
50-
]
54+
assert call_made[2]['body'] == self.expectedImpressions
5155

5256
httpclient.reset_mock()
5357
def raise_exception(*args, **kwargs):
5458
raise client.HttpClientException('some_message')
5559
httpclient.post.side_effect = raise_exception
5660
with pytest.raises(APIException) as exc_info:
57-
response = impressions_api.flush_impressions([
58-
Impression('k1', 'f1', 'on', 'l1', 123456, 'b1', 321654),
59-
Impression('k2', 'f2', 'off', 'l1', 123456, 'b1', 321654),
60-
Impression('k3', 'f1', 'on', 'l1', 123456, 'b1', 321654),
61-
])
61+
response = impressions_api.flush_impressions(self.impressions)
6262
assert exc_info.type == APIException
6363
assert exc_info.value.message == 'some_message'
64+
65+
def test_post_impressions_ip_address_disabled(self, mocker):
66+
"""Test impressions posting API call."""
67+
httpclient = mocker.Mock(spec=client.HttpClient)
68+
httpclient.post.return_value = client.HttpResponse(200, '')
69+
cfg = DEFAULT_CONFIG.copy()
70+
cfg.update({'ipAddressesEnabled': False})
71+
sdk_metadata = get_metadata(cfg)
72+
impressions_api = impressions.ImpressionsAPI(httpclient, 'some_api_key', sdk_metadata)
73+
response = impressions_api.flush_impressions(self.impressions)
74+
75+
call_made = httpclient.post.mock_calls[0]
76+
77+
# validate positional arguments
78+
assert call_made[1] == ('events', '/testImpressions/bulk', 'some_api_key')
79+
80+
# validate key-value args (headers)
81+
assert call_made[2]['extra_headers'] == {
82+
'SplitSDKVersion': 'python-%s' % __version__,
83+
}
84+
85+
# validate key-value args (body)
86+
assert call_made[2]['body'] == self.expectedImpressions

tests/client/test_utils.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
11
"""Split client utilities test module."""
22
#pylint: disable=no-self-use,too-few-public-methods
33

4+
import socket
5+
6+
47
from splitio.client import util, config
58
from splitio.version import __version__
9+
from splitio.client.config import DEFAULT_CONFIG
610

711
class ClientUtilsTests(object):
812
"""Client utilities test cases."""
@@ -25,6 +29,12 @@ def test_get_metadata(self, mocker):
2529
assert get_ip_mock.mock_calls == [mocker.call()]
2630
assert get_host_mock.mock_calls == [mocker.call(mocker.ANY)]
2731

32+
cfg = DEFAULT_CONFIG.copy()
33+
cfg.update({'ipAddressesEnabled': False})
34+
meta = util.get_metadata(cfg)
35+
assert meta.instance_ip == 'NA'
36+
assert meta.instance_name == 'NA'
37+
2838
get_ip_mock.reset_mock()
2939
get_host_mock.reset_mock()
3040
meta = util.get_metadata({})

0 commit comments

Comments
 (0)