Skip to content

Commit 125faa3

Browse files
committed
Moved all methods outside strategy class except one.
1 parent 95138b6 commit 125faa3

5 files changed

Lines changed: 53 additions & 77 deletions

File tree

splitio/engine/impressions.py

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,13 @@
44
from splitio.client.listener import ImpressionListenerException
55
from splitio.engine.strategies.strategy_debug_mode import StrategyDebugMode
66
from splitio.engine.strategies.strategy_optimized_mode import StrategyOptimizedMode
7+
from splitio.engine.strategies import Observer, Counter
78

89
import logging
910
_LOGGER = logging.getLogger(__name__)
1011

12+
_IMPRESSION_OBSERVER_CACHE_SIZE = 500000
13+
1114
class ImpressionsMode(Enum):
1215
"""Impressions tracking mode."""
1316

@@ -30,6 +33,8 @@ def __init__(self, mode=ImpressionsMode.OPTIMIZED, standalone=True, listener=Non
3033
:param listener: Optional impressions listener that will capture all seen impressions.
3134
:type listener: splitio.client.listener.ImpressionListenerWrapper
3235
"""
36+
self._observer = Observer(_IMPRESSION_OBSERVER_CACHE_SIZE) if standalone else None
37+
self._counter = Counter() if standalone else None
3338
self._strategy = self.get_strategy(mode, standalone)
3439
self._listener = listener
3540

@@ -40,7 +45,7 @@ def get_strategy(self, mode, standalone):
4045
:returns: A strategy object
4146
:rtype: (BaseStrategy)
4247
"""
43-
return StrategyOptimizedMode(standalone) if mode == ImpressionsMode.OPTIMIZED else StrategyDebugMode(standalone)
48+
return StrategyOptimizedMode(self._counter, self._observer, standalone) if mode == ImpressionsMode.OPTIMIZED else StrategyDebugMode(self._observer, standalone)
4449

4550
def process_impressions(self, impressions):
4651
"""
@@ -51,9 +56,9 @@ def process_impressions(self, impressions):
5156
:param impressions: List of impression objects with attributes
5257
:type impressions: list[tuple[splitio.models.impression.Impression, dict]]
5358
"""
54-
imps = self._strategy.process_impressions(impressions)
55-
self._send_impressions_to_listener(imps)
56-
return self._strategy.truncate_impressions_time(imps)
59+
for_log, for_listener = self._strategy.process_impressions(impressions)
60+
self._send_impressions_to_listener(for_listener)
61+
return for_log
5762

5863
def get_counts(self):
5964
"""
@@ -62,7 +67,7 @@ def get_counts(self):
6267
:returns: A list of counter objects.
6368
:rtype: list[Counter.CountPerFeature]
6469
"""
65-
return self._strategy.get_counts()
70+
return self._counter.pop_all() if self._counter is not None else []
6671

6772
def _send_impressions_to_listener(self, impressions):
6873
"""

splitio/engine/strategies/__init__.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,22 @@ def truncate_time(timestamp_ms):
1919
"""
2020
return timestamp_ms - (timestamp_ms % _TIME_INTERVAL_MS)
2121

22+
def truncate_impressions_time(imps, counter = None):
23+
"""
24+
Process impressions.
25+
26+
Impressions are truncated based on time
27+
28+
:param impressions: List of impression objects with attributes
29+
:type impressions: list[tuple[splitio.models.impression.Impression, dict]]
30+
31+
:returns: truncated list of impressions
32+
:rtype: list[splitio.models.impression.Impression]
33+
"""
34+
this_hour = truncate_time(util.utctime_ms())
35+
return [imp for imp, _ in imps] if counter is None \
36+
else [i for i, _ in imps if i.previous_time is None or i.previous_time < this_hour]
37+
2238

2339
class Hasher(object): # pylint:disable=too-few-public-methods
2440
"""Impression hasher."""
Lines changed: 5 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,18 @@
11
from splitio.engine.strategies.base_strategy import BaseStrategy
2-
from splitio.engine.strategies import Observer
2+
from splitio.engine.strategies import Observer, truncate_impressions_time
33

44
_IMPRESSION_OBSERVER_CACHE_SIZE = 500000
55

66
class StrategyDebugMode(BaseStrategy):
77
"""Debug mode strategy."""
88

9-
def __init__(self, standalone=True):
9+
def __init__(self, observer=None, standalone=True):
1010
"""
1111
Construct a strategy instance for debug mode.
1212
1313
"""
1414
self._standalone = standalone
15-
self._observer = Observer(_IMPRESSION_OBSERVER_CACHE_SIZE) if self._standalone else None
15+
self._observer = observer
1616

1717
def process_impressions(self, impressions):
1818
"""
@@ -26,23 +26,5 @@ def process_impressions(self, impressions):
2626
:returns: Observed list of impressions
2727
:rtype: list[tuple[splitio.models.impression.Impression, dict]]
2828
"""
29-
imps = [(self._observer.test_and_set(imp), attrs) for imp, attrs in impressions] if self._observer is not None else impressions
30-
return imps
31-
32-
def truncate_impressions_time(self, imps):
33-
"""
34-
No counter implemented, return same impresisons passed.
35-
36-
:returns: list of impressions
37-
:rtype: list[splitio.models.impression.Impression]
38-
"""
39-
return [imp for imp, _ in imps]
40-
41-
def get_counts(self):
42-
"""
43-
No counter implemented, return empty array
44-
45-
:returns: empty list
46-
:rtype: list[]
47-
"""
48-
return []
29+
for_listener = [(self._observer.test_and_set(imp), attrs) for imp, attrs in impressions] if self._observer is not None else impressions
30+
return truncate_impressions_time(for_listener, None), for_listener
Lines changed: 7 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,18 @@
11
from splitio.engine.strategies.base_strategy import BaseStrategy
2-
from splitio.engine.strategies import Observer, Counter, truncate_time
2+
from splitio.engine.strategies import Observer, Counter, truncate_impressions_time
33
from splitio import util
44

5-
_IMPRESSION_OBSERVER_CACHE_SIZE = 500000
6-
75
class StrategyOptimizedMode(BaseStrategy):
86
"""Optimized mode strategy."""
97

10-
def __init__(self, standalone=True):
8+
def __init__(self, counter=None, observer=None, standalone=True):
119
"""
1210
Construct a strategy instance for optimized mode.
1311
1412
"""
1513
self._standalone = standalone
16-
self._counter = Counter() if self._standalone else None
17-
self._observer = Observer(_IMPRESSION_OBSERVER_CACHE_SIZE) if self._standalone else None
14+
self._counter = counter
15+
self._observer = observer
1816

1917
def process_impressions(self, impressions):
2018
"""
@@ -28,33 +26,7 @@ def process_impressions(self, impressions):
2826
:returns: Observed list of impressions
2927
:rtype: list[tuple[splitio.models.impression.Impression, dict]]
3028
"""
31-
imps = [(self._observer.test_and_set(imp), attrs) for imp, attrs in impressions] \
32-
if self._observer else impressions
29+
forListener = [(self._observer.test_and_set(imp), attrs) for imp, attrs in impressions] if self._observer else impressions
3330
if self._counter is not None:
34-
self._counter.track([imp for imp, _ in imps])
35-
return imps
36-
37-
def truncate_impressions_time(self, imps):
38-
"""
39-
Process impressions.
40-
41-
Impressions are truncated based on time
42-
43-
:param impressions: List of impression objects with attributes
44-
:type impressions: list[tuple[splitio.models.impression.Impression, dict]]
45-
46-
:returns: truncated list of impressions
47-
:rtype: list[splitio.models.impression.Impression]
48-
"""
49-
this_hour = truncate_time(util.utctime_ms())
50-
return [imp for imp, _ in imps] if self._counter is None \
51-
else [i for i, _ in imps if i.previous_time is None or i.previous_time < this_hour]
52-
53-
def get_counts(self):
54-
"""
55-
Return counts of impressions per features.
56-
57-
:returns: A list of counter objects.
58-
:rtype: list[Counter.CountPerFeature]
59-
"""
60-
return self._counter.pop_all() if self._counter is not None else []
31+
self._counter.track([imp for imp, _ in forListener])
32+
return truncate_impressions_time(forListener, self._counter), forListener

tests/engine/test_impressions.py

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
from splitio.engine.strategies.strategy_optimized_mode import StrategyOptimizedMode
77
from splitio.models.impressions import Impression
88
from splitio.client.listener import ImpressionListenerWrapper
9+
import pytest
910

1011
def utctime_ms_reimplement():
1112
"""Re-implementation of utctime_ms to avoid conflicts with mock/patching."""
@@ -100,7 +101,7 @@ def test_standalone_optimized(self, mocker):
100101
mocker.patch('splitio.util.utctime_ms', new=utc_time_mock)
101102

102103
manager = Manager() # no listener
103-
assert manager._strategy._counter is not None
104+
assert manager._counter is not None
104105
assert manager._strategy._observer is not None
105106
assert manager._listener is None
106107
assert isinstance(manager._strategy, StrategyOptimizedMode)
@@ -115,7 +116,7 @@ def test_standalone_optimized(self, mocker):
115116
Impression('k1', 'f2', 'on', 'l1', 123, None, utc_now-3)]
116117

117118
assert [Counter.CountPerFeature(k.feature, k.timeframe, v)
118-
for (k, v) in manager._strategy._counter._data.items()] == [
119+
for (k, v) in manager._counter._data.items()] == [
119120
Counter.CountPerFeature('f1', truncate_time(utc_now-3), 1),
120121
Counter.CountPerFeature('f2', truncate_time(utc_now-3), 1)]
121122

@@ -145,9 +146,9 @@ def test_standalone_optimized(self, mocker):
145146
Impression('k2', 'f1', 'on', 'l1', 123, None, utc_now-2, old_utc-1)]
146147

147148
assert len(manager._strategy._observer._cache._data) == 3 # distinct impressions seen
148-
assert len(manager._strategy._counter._data) == 3 # 2 distinct features. 1 seen in 2 different timeframes
149+
assert len(manager._counter._data) == 3 # 2 distinct features. 1 seen in 2 different timeframes
149150

150-
assert set(manager._strategy._counter.pop_all()) == set([
151+
assert set(manager._counter.pop_all()) == set([
151152
Counter.CountPerFeature('f1', truncate_time(old_utc), 3),
152153
Counter.CountPerFeature('f2', truncate_time(old_utc), 1),
153154
Counter.CountPerFeature('f1', truncate_time(utc_now), 2)
@@ -163,7 +164,7 @@ def test_standalone_debug(self, mocker):
163164
mocker.patch('splitio.util.utctime_ms', new=utc_time_mock)
164165

165166
manager = Manager(ImpressionsMode.DEBUG) # no listener
166-
assert manager._strategy.get_counts() == []
167+
assert manager.get_counts() == []
167168
assert manager._strategy._observer is not None
168169
assert manager._listener is None
169170
assert isinstance(manager._strategy, StrategyDebugMode)
@@ -213,7 +214,7 @@ def test_non_standalone_optimized(self, mocker):
213214
mocker.patch('splitio.util.utctime_ms', new=utc_time_mock)
214215

215216
manager = Manager(ImpressionsMode.OPTIMIZED, False) # no listener
216-
assert manager._strategy._counter is None
217+
assert manager._counter is None
217218
assert manager._strategy._observer is None
218219
assert manager._listener is None
219220
assert isinstance(manager._strategy, StrategyOptimizedMode)
@@ -260,7 +261,7 @@ def test_non_standalone_debug(self, mocker):
260261
mocker.patch('splitio.util.utctime_ms', new=utc_time_mock)
261262

262263
manager = Manager(ImpressionsMode.DEBUG, False) # no listener
263-
assert manager._strategy.get_counts() == []
264+
assert manager.get_counts() == []
264265
assert manager._strategy._observer is None
265266
assert manager._listener is None
266267
assert isinstance(manager._strategy, StrategyDebugMode)
@@ -309,7 +310,7 @@ def test_standalone_optimized_listener(self, mocker):
309310
listener = mocker.Mock(spec=ImpressionListenerWrapper)
310311

311312
manager = Manager(listener=listener) # no listener
312-
assert manager._strategy._counter is not None
313+
assert manager._counter is not None
313314
assert manager._strategy._observer is not None
314315
assert manager._listener is not None
315316
assert isinstance(manager._strategy, StrategyOptimizedMode)
@@ -322,7 +323,7 @@ def test_standalone_optimized_listener(self, mocker):
322323
assert imps == [Impression('k1', 'f1', 'on', 'l1', 123, None, utc_now-3),
323324
Impression('k1', 'f2', 'on', 'l1', 123, None, utc_now-3)]
324325
assert [Counter.CountPerFeature(k.feature, k.timeframe, v)
325-
for (k, v) in manager._strategy._counter._data.items()] == [
326+
for (k, v) in manager._counter._data.items()] == [
326327
Counter.CountPerFeature('f1', truncate_time(utc_now-3), 1),
327328
Counter.CountPerFeature('f2', truncate_time(utc_now-3), 1)]
328329

@@ -352,9 +353,9 @@ def test_standalone_optimized_listener(self, mocker):
352353
Impression('k2', 'f1', 'on', 'l1', 123, None, utc_now-2, old_utc-1)]
353354

354355
assert len(manager._strategy._observer._cache._data) == 3 # distinct impressions seen
355-
assert len(manager._strategy._counter._data) == 3 # 2 distinct features. 1 seen in 2 different timeframes
356+
assert len(manager._counter._data) == 3 # 2 distinct features. 1 seen in 2 different timeframes
356357

357-
assert set(manager._strategy._counter.pop_all()) == set([
358+
assert set(manager._counter.pop_all()) == set([
358359
Counter.CountPerFeature('f1', truncate_time(old_utc), 3),
359360
Counter.CountPerFeature('f2', truncate_time(old_utc), 1),
360361
Counter.CountPerFeature('f1', truncate_time(utc_now), 2)
@@ -381,7 +382,7 @@ def test_standalone_debug_listener(self, mocker):
381382
imps = []
382383
listener = mocker.Mock(spec=ImpressionListenerWrapper)
383384
manager = Manager(ImpressionsMode.DEBUG, listener=listener)
384-
assert manager._strategy.get_counts() == []
385+
assert manager.get_counts() == []
385386
assert manager._strategy._observer is not None
386387
assert manager._listener is not None
387388
assert isinstance(manager._strategy, StrategyDebugMode)
@@ -442,7 +443,7 @@ def test_non_standalone_optimized_listener(self, mocker):
442443
imps = []
443444
listener = mocker.Mock(spec=ImpressionListenerWrapper)
444445
manager = Manager(ImpressionsMode.OPTIMIZED, False, listener) # no listener
445-
assert manager._strategy._counter is None
446+
assert manager._counter is None
446447
assert manager._strategy._observer is None
447448
assert manager._listener is not None
448449
assert isinstance(manager._strategy, StrategyOptimizedMode)
@@ -500,7 +501,7 @@ def test_non_standalone_debug_listener(self, mocker):
500501

501502
listener = mocker.Mock(spec=ImpressionListenerWrapper)
502503
manager = Manager(ImpressionsMode.DEBUG, False, listener) # no listener
503-
assert manager._strategy.get_counts() == []
504+
assert manager.get_counts() == []
504505
assert manager._strategy._observer is None
505506
assert manager._listener is not None
506507
assert isinstance(manager._strategy, StrategyDebugMode)

0 commit comments

Comments
 (0)