Skip to content

Commit 686a509

Browse files
author
Matias Melograno
committed
adding test coverage
1 parent 0a5597d commit 686a509

File tree

4 files changed

+106
-36
lines changed

4 files changed

+106
-36
lines changed

splitio/client/factory.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -441,6 +441,10 @@ def _build_uwsgi_factory(api_key, cfg):
441441
storages['events'],
442442
storages['impressions'],
443443
)
444+
_LOGGER.warning(
445+
"Beware: uwsgi-cache based operation mode is soon to be deprecated. Please consider " +
446+
"redis if you need a centralized point of syncrhonization, or in-memory (with preforking " +
447+
"support enabled) if running uwsgi with a master and several http workers)")
444448
return SplitFactory(
445449
api_key,
446450
storages,

tests/client/test_client.py

Lines changed: 33 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
import json
55
import os
6-
from splitio.client.client import Client, _LOGGER as _logger
6+
from splitio.client.client import Client, _LOGGER as _logger, CONTROL
77
from splitio.client.factory import SplitFactory
88
from splitio.engine.evaluator import Evaluator
99
from splitio.models.impressions import Impression, Label
@@ -357,40 +357,38 @@ def _get_storage_mock(name):
357357
assert client.destroyed is not None
358358
assert destroyed_mock.mock_calls == [mocker.call()]
359359

360-
def test_track(self, mocker):
361-
"""Test that destroy/destroyed calls are forwarded to the factory."""
362-
split_storage = mocker.Mock(spec=SplitStorage)
363-
segment_storage = mocker.Mock(spec=SegmentStorage)
364-
impression_storage = mocker.Mock(spec=ImpressionStorage)
365-
event_storage = mocker.Mock(spec=EventStorage)
366-
event_storage.put.return_value = True
367-
telemetry_storage = mocker.Mock(spec=TelemetryStorage)
360+
def test_evaluations_before_running_post_fork(self, mocker):
361+
destroyed_property = mocker.PropertyMock()
362+
destroyed_property.return_value = False
368363

369-
def _get_storage_mock(name):
370-
return {
371-
'splits': split_storage,
372-
'segments': segment_storage,
373-
'impressions': impression_storage,
374-
'events': event_storage,
375-
'telemetry': telemetry_storage
376-
}[name]
377364
factory = mocker.Mock(spec=SplitFactory)
378-
factory._get_storage = _get_storage_mock
379-
destroyed_mock = mocker.PropertyMock()
380-
destroyed_mock.return_value = False
381-
factory._waiting_fork.return_value = False
382-
type(factory).destroyed = destroyed_mock
383-
factory._apikey = 'test'
384-
mocker.patch('splitio.client.client.utctime_ms', new=lambda: 1000)
365+
factory._waiting_fork.return_value = True
366+
type(factory).destroyed = destroyed_property
385367

386-
impmanager = mocker.Mock(spec=ImpressionManager)
387-
recorder = StandardRecorder(impmanager, telemetry_storage, event_storage,
388-
impression_storage)
389-
client = Client(factory, recorder, True)
390-
assert client.track('key', 'user', 'purchase', 12) is True
391-
assert mocker.call([
392-
EventWrapper(
393-
event=Event('key', 'user', 'purchase', 12, 1000, None),
394-
size=1024
395-
)
396-
]) in event_storage.put.mock_calls
368+
expected_msg = [
369+
mocker.call('Client is not ready - no calls possible')
370+
]
371+
372+
client = Client(factory, mocker.Mock())
373+
_logger = mocker.Mock()
374+
mocker.patch('splitio.client.client._LOGGER', new=_logger)
375+
376+
assert client.get_treatment('some_key', 'some_feature') == CONTROL
377+
assert _logger.error.mock_calls == expected_msg
378+
_logger.reset_mock()
379+
380+
assert client.get_treatment_with_config('some_key', 'some_feature') == (CONTROL, None)
381+
assert _logger.error.mock_calls == expected_msg
382+
_logger.reset_mock()
383+
384+
assert client.track("some_key", "traffic_type", "event_type", None) is False
385+
assert _logger.error.mock_calls == expected_msg
386+
_logger.reset_mock()
387+
388+
assert client.get_treatments(None, ['some_feature']) == {'some_feature': CONTROL}
389+
assert _logger.error.mock_calls == expected_msg
390+
_logger.reset_mock()
391+
392+
assert client.get_treatments_with_config('some_key', ['some_feature']) == {'some_feature': (CONTROL, None)}
393+
assert _logger.error.mock_calls == expected_msg
394+
_logger.reset_mock()

tests/client/test_factory.py

Lines changed: 62 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
import time
66
import threading
7-
from splitio.client.factory import get_factory, SplitFactory, _INSTANTIATED_FACTORIES
7+
from splitio.client.factory import get_factory, SplitFactory, _INSTANTIATED_FACTORIES, Status
88
from splitio.client.config import DEFAULT_CONFIG
99
from splitio.storage import redis, inmemmory, uwsgi
1010
from splitio.tasks import events_sync, impressions_sync, split_sync, segment_sync, telemetry_sync
@@ -161,6 +161,28 @@ def test_uwsgi_client_creation(self):
161161
assert factory.ready
162162
factory.destroy()
163163

164+
def test_uwsgi_forked_client_creation(self):
165+
"""Test client with preforked initialization."""
166+
factory = get_factory('some_api_key', config={'preforkedInitialization': True})
167+
assert isinstance(factory._storages['splits'], inmemmory.InMemorySplitStorage)
168+
assert isinstance(factory._storages['segments'], inmemmory.InMemorySegmentStorage)
169+
assert isinstance(factory._storages['impressions'], inmemmory.InMemoryImpressionStorage)
170+
assert factory._storages['impressions']._impressions.maxsize == 10000
171+
assert isinstance(factory._storages['events'], inmemmory.InMemoryEventStorage)
172+
assert factory._storages['events']._events.maxsize == 10000
173+
assert isinstance(factory._storages['telemetry'], inmemmory.InMemoryTelemetryStorage)
174+
175+
assert isinstance(factory._sync_manager, Manager)
176+
177+
assert isinstance(factory._recorder, StandardRecorder)
178+
assert isinstance(factory._recorder._impressions_manager, ImpressionsManager)
179+
assert isinstance(factory._recorder._telemetry_storage, inmemmory.TelemetryStorage)
180+
assert isinstance(factory._recorder._event_sotrage, inmemmory.EventStorage)
181+
assert isinstance(factory._recorder._impression_storage, inmemmory.ImpressionStorage)
182+
183+
assert factory._status == Status.WAITING_FORK
184+
factory.destroy()
185+
164186
def test_destroy(self, mocker):
165187
"""Test that tasks are shutdown and data is flushed when destroy is called."""
166188

@@ -461,3 +483,42 @@ def _make_factory_with_apikey(apikey, *_, **__):
461483
factory2.destroy()
462484
factory3.destroy()
463485
factory4.destroy()
486+
487+
def test_uwsgi_preforked(self, mocker):
488+
"""Test preforked initializations."""
489+
global called_sync_all
490+
called_sync_all = 0
491+
global called_start
492+
called_start = 0
493+
global called_recreate
494+
called_recreate = 0
495+
496+
# Mocking
497+
def _sync_all(self):
498+
print('here')
499+
global called_sync_all
500+
called_sync_all += 1
501+
mocker.patch('splitio.sync.synchronizer.Synchronizer.sync_all', new=_sync_all)
502+
503+
def _start(self):
504+
global called_start
505+
called_start += 1
506+
mocker.patch('splitio.sync.manager.Manager.start', new=_start)
507+
508+
def _recreate(self):
509+
global called_recreate
510+
called_recreate += 1
511+
mocker.patch('splitio.sync.manager.Manager.recreate', new=_recreate)
512+
513+
config = {
514+
'preforkedInitialization': True,
515+
}
516+
factory = get_factory("none", config=config)
517+
factory.block_until_ready(10)
518+
assert factory._status == Status.WAITING_FORK
519+
assert called_sync_all == 1
520+
assert called_start == 0
521+
522+
factory.handle_post_fork()
523+
assert called_recreate == 1
524+
assert called_start == 1

tests/sync/test_segments_synchronizer.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,3 +128,10 @@ def fetch_segment_mock(segment_name, change_number):
128128
api_calls = [call for call in api.fetch_segment.mock_calls]
129129
assert mocker.call('segmentA', -1) in api_calls
130130
assert mocker.call('segmentA', 123) in api_calls
131+
132+
def test_recreate(self, mocker):
133+
"""Test recreate logic."""
134+
segments_synchronizer = SegmentSynchronizer(mocker.Mock(), mocker.Mock(), mocker.Mock())
135+
current_pool = segments_synchronizer._worker_pool
136+
segments_synchronizer.recreate()
137+
assert segments_synchronizer._worker_pool != current_pool

0 commit comments

Comments
 (0)