Skip to content

Commit c7d367a

Browse files
authored
fix: Move tests under ldclient namespace (#29) (#283)
Previous distributions of this package included two packages -- ldclient and testing. This top level testing namespace can conflict with other packages. In fact, it conflicts with our own eventsource library. In general this doesn't matter, but it may if: 1. You are using a build process that warns about conflicts (see [this issue][1]) 2. You want to install the sdist on an unsupported platform and would like to be able to verify the tests. To resolve this issue, we are moving the testing folder into the ldclient package. These testing files will only be included in the sdist format. This allows for a smaller wheel size while also allowing for flexibility with consumers. [1]: #281
1 parent 1ddf148 commit c7d367a

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

69 files changed

+105
-105
lines changed

Makefile

+1-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ test: install
3333
.PHONY: lint
3434
lint: #! Run type analysis and linting checks
3535
lint: install
36-
@poetry run mypy ldclient testing
36+
@poetry run mypy ldclient
3737

3838
#
3939
# Documentation generation
File renamed without changes.
File renamed without changes.

testing/feature_store_test_base.py ldclient/testing/feature_store_test_base.py

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
from ldclient.interfaces import FeatureStore
22
from ldclient.versioned_data_kind import FEATURES
33

4-
from testing.builders import *
4+
from ldclient.testing.builders import *
55

66
from abc import abstractmethod
77
import pytest
@@ -21,11 +21,11 @@ def create_feature_store(self) -> FeatureStore:
2121
class StoreTestScope:
2222
def __init__(self, store: FeatureStore):
2323
self.__store = store
24-
24+
2525
@property
2626
def store(self) -> FeatureStore:
2727
return self.__store
28-
28+
2929
# These magic methods allow the scope to be automatically cleaned up in a "with" block
3030
def __enter__(self):
3131
return self.__store
@@ -59,7 +59,7 @@ def inited_store(self, tester):
5959
}
6060
})
6161
return scope
62-
62+
6363
@staticmethod
6464
def make_feature(key, ver):
6565
return FlagBuilder(key).version(ver).on(True).variations(True, False).salt('abc').build()

testing/http_util.py ldclient/testing/http_util.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ def __init__(self, port, secure):
4848
self.server = HTTPServer(('localhost', port), MockServerRequestHandler)
4949
if secure:
5050
context = SSLContext(PROTOCOL_TLSv1_2)
51-
context.load_cert_chain('./testing/selfsigned.pem', './testing/selfsigned.key')
51+
context.load_cert_chain('./ldclient/testing/selfsigned.pem', './ldclient/testing/selfsigned.key')
5252
self.server.socket = context.wrap_socket(
5353
self.server.socket,
5454
server_side=True
File renamed without changes.

testing/impl/datasource/test_feature_requester.py ldclient/testing/impl/datasource/test_feature_requester.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22
from ldclient.impl.datasource.feature_requester import FeatureRequesterImpl
33
from ldclient.version import VERSION
44
from ldclient.versioned_data_kind import FEATURES, SEGMENTS
5-
from testing.http_util import start_server, BasicResponse, JsonResponse
6-
from testing.proxy_test_util import do_proxy_tests
5+
from ldclient.testing.http_util import start_server, BasicResponse, JsonResponse
6+
from ldclient.testing.proxy_test_util import do_proxy_tests
77

88
def test_get_all_data_returns_data():
99
with start_server() as server:

testing/impl/datasource/test_polling_processor.py ldclient/testing/impl/datasource/test_polling_processor.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,9 @@
1111
from ldclient.interfaces import DataSourceStatus, DataSourceState, DataSourceErrorKind
1212
from ldclient.versioned_data_kind import FEATURES, SEGMENTS
1313

14-
from testing.builders import *
15-
from testing.stub_util import MockFeatureRequester, MockResponse
16-
from testing.test_util import SpyListener
14+
from ldclient.testing.builders import *
15+
from ldclient.testing.stub_util import MockFeatureRequester, MockResponse
16+
from ldclient.testing.test_util import SpyListener
1717

1818
pp = None
1919
mock_requester = None

testing/impl/datasource/test_streaming.py ldclient/testing/impl/datasource/test_streaming.py

+5-5
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,11 @@
1313
from ldclient.interfaces import DataSourceStatus, DataSourceState, DataSourceErrorKind
1414
from ldclient.impl.datasource.status import DataSourceUpdateSinkImpl
1515

16-
from testing.builders import *
17-
from testing.http_util import start_server, BasicResponse, CauseNetworkError, SequentialHandler
18-
from testing.proxy_test_util import do_proxy_tests
19-
from testing.stub_util import make_delete_event, make_patch_event, make_put_event, make_invalid_put_event, stream_content
20-
from testing.test_util import SpyListener
16+
from ldclient.testing.builders import *
17+
from ldclient.testing.http_util import start_server, BasicResponse, CauseNetworkError, SequentialHandler
18+
from ldclient.testing.proxy_test_util import do_proxy_tests
19+
from ldclient.testing.stub_util import make_delete_event, make_patch_event, make_put_event, make_invalid_put_event, stream_content
20+
from ldclient.testing.test_util import SpyListener
2121

2222
brief_delay = 0.001
2323

testing/impl/evaluator_util.py ldclient/testing/impl/evaluator_util.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
from ldclient.impl.evaluator import Evaluator, _make_big_segment_ref
44
from ldclient.impl.events.types import EventFactory
55
from ldclient.impl.model import *
6-
from testing.builders import *
6+
from ldclient.testing.builders import *
77

88
from typing import Any, Optional, Tuple, Union
99

File renamed without changes.

testing/impl/events/test_event_factory.py ldclient/testing/impl/events/test_event_factory.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
from ldclient.evaluation import EvaluationDetail
33
from ldclient.impl.events.types import EventFactory
44

5-
from testing.builders import *
5+
from ldclient.testing.builders import *
66

77
_event_factory_default = EventFactory(False)
88
_user = Context.create('x')

testing/impl/events/test_event_processor.py ldclient/testing/impl/events/test_event_processor.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,9 @@
1717
from ldclient.impl.util import timedelta_millis
1818
from ldclient.impl.events.event_context_formatter import EventContextFormatter
1919

20-
from testing.builders import *
21-
from testing.proxy_test_util import do_proxy_tests
22-
from testing.stub_util import MockHttp
20+
from ldclient.testing.builders import *
21+
from ldclient.testing.proxy_test_util import do_proxy_tests
22+
from ldclient.testing.stub_util import MockHttp
2323

2424

2525
default_config = Config("fake_sdk_key")

testing/impl/events/test_event_summarizer.py ldclient/testing/impl/events/test_event_summarizer.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
from ldclient.impl.events.event_summarizer import EventSummarizer, EventSummaryCounter, EventSummaryFlag
33
from ldclient.impl.events.types import *
44

5-
from testing.builders import *
5+
from ldclient.testing.builders import *
66

77

88
user = Context.create('user1')
File renamed without changes.

testing/impl/test_big_segments.py ldclient/testing/impl/test_big_segments.py

+7-7
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
from ldclient.evaluation import BigSegmentsStatus
33
from ldclient.impl.big_segments import BigSegmentStoreManager, _hash_for_user_key
44
from ldclient.interfaces import BigSegmentStoreMetadata
5-
from testing.mock_components import MockBigSegmentStore
5+
from ldclient.testing.mock_components import MockBigSegmentStore
66

77
from queue import Queue
88
import time
@@ -108,20 +108,20 @@ def test_membership_query_least_recent_context_evicted_from_cache():
108108
result3 = manager.get_user_membership(user_key_3)
109109

110110
assert store.membership_queries == [user_hash_1, user_hash_2, user_hash_3]
111-
111+
112112
# Since the capacity is only 2 and user_key_1 was the least recently used, that key should be
113113
# evicted by the user_key_3 query. Now only user_key_2 and user_key_3 are in the cache, and
114114
# querying them again should not cause a new query to the store.
115115
result2a = manager.get_user_membership(user_key_2)
116116
result3a = manager.get_user_membership(user_key_3)
117117
assert result2a == result2
118118
assert result3a == result3
119-
119+
120120
assert store.membership_queries == [user_hash_1, user_hash_2, user_hash_3]
121-
121+
122122
result1a = manager.get_user_membership(user_key_1)
123123
assert result1a == result1
124-
124+
125125
assert store.membership_queries == [user_hash_1, user_hash_2, user_hash_3, user_hash_1]
126126
finally:
127127
manager.stop()
@@ -130,7 +130,7 @@ def test_status_polling_detects_store_unavailability():
130130
store = MockBigSegmentStore()
131131
store.setup_metadata_always_up_to_date()
132132
statuses = Queue()
133-
133+
134134
manager = BigSegmentStoreManager(BigSegmentsConfig(store=store, status_poll_interval=0.01))
135135

136136
try:
@@ -155,7 +155,7 @@ def test_status_polling_detects_stale_status():
155155
store = MockBigSegmentStore()
156156
store.setup_metadata_always_up_to_date()
157157
statuses = Queue()
158-
158+
159159
manager = BigSegmentStoreManager(BigSegmentsConfig(store=store, status_poll_interval=0.01))
160160

161161
try:

testing/impl/test_data_sink.py ldclient/testing/impl/test_data_sink.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@
99
from ldclient.impl.listeners import Listeners
1010
from ldclient.versioned_data_kind import FEATURES, SEGMENTS
1111

12-
from testing.test_util import SpyListener
13-
from testing.builders import FlagBuilder, FlagRuleBuilder, make_clause, SegmentBuilder, SegmentRuleBuilder
12+
from ldclient.testing.test_util import SpyListener
13+
from ldclient.testing.builders import FlagBuilder, FlagRuleBuilder, make_clause, SegmentBuilder, SegmentRuleBuilder
1414

1515

1616
@pytest.fixture

testing/impl/test_evaluator.py ldclient/testing/impl/test_evaluator.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
from ldclient.client import Context
22
from ldclient.evaluation import EvaluationDetail
3-
from testing.builders import *
4-
from testing.impl.evaluator_util import *
3+
from ldclient.testing.builders import *
4+
from ldclient.testing.impl.evaluator_util import *
55

66

77
def test_flag_returns_off_variation_if_flag_is_off():
@@ -100,5 +100,5 @@ def test_segment_match_clause_falls_through_with_no_errors_if_segment_not_found(
100100
user = Context.create('foo')
101101
flag = make_boolean_flag_with_clauses(make_clause_matching_segment_key('segkey'))
102102
evaluator = EvaluatorBuilder().with_unknown_segment('segkey').build()
103-
103+
104104
assert evaluator.evaluate(flag, user, event_factory).detail.value == False

testing/impl/test_evaluator_big_segment.py ldclient/testing/impl/test_evaluator_big_segment.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import pytest
22

33
from ldclient.evaluation import BigSegmentsStatus
4-
from testing.builders import *
5-
from testing.impl.evaluator_util import *
4+
from ldclient.testing.builders import *
5+
from ldclient.testing.impl.evaluator_util import *
66

77

88
def test_big_segment_with_no_generation_is_not_matched():
@@ -30,7 +30,7 @@ def _test_matched_with_include(non_default_kind: bool, multi_kind_context: bool)
3030
single_kind_context = Context.create(target_key, 'kind1') if non_default_kind else Context.create(target_key)
3131
eval_context = Context.create_multi(single_kind_context, Context.create('key2', 'kind2')) if multi_kind_context \
3232
else single_kind_context
33-
33+
3434
segment = SegmentBuilder('key').version(1) \
3535
.unbounded(True) \
3636
.unbounded_context_kind('kind1' if non_default_kind else None) \

testing/impl/test_evaluator_bucketing.py ldclient/testing/impl/test_evaluator_bucketing.py

+5-5
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22
from ldclient.impl.evaluator import _bucket_context, _variation_index_for_context
33
from ldclient.impl.model import *
44

5-
from testing.builders import *
6-
from testing.impl.evaluator_util import *
5+
from ldclient.testing.builders import *
6+
from ldclient.testing.impl.evaluator_util import *
77

88
import math
99
import pytest
@@ -22,7 +22,7 @@ def test_variation_index_is_returned_for_bucket(self):
2222
# so we can construct a rollout whose second bucket just barely contains that value
2323
bucket_value = math.trunc(_bucket_context(None, user, None, flag.key, flag.salt, None) * 100000)
2424
assert bucket_value > 0 and bucket_value < 100000
25-
25+
2626
bad_variation_a = 0
2727
matched_variation = 1
2828
bad_variation_b = 2
@@ -44,7 +44,7 @@ def test_last_bucket_is_used_if_bucket_value_equals_total_weight(self):
4444

4545
# We'll construct a list of variations that stops right at the target bucket value
4646
bucket_value = math.trunc(_bucket_context(None, user, None, flag.key, flag.salt, None) * 100000)
47-
47+
4848
rule = VariationOrRollout({
4949
'rollout': {
5050
'variations': [
@@ -54,7 +54,7 @@ def test_last_bucket_is_used_if_bucket_value_equals_total_weight(self):
5454
})
5555
result_variation = _variation_index_for_context(flag, rule, user)
5656
assert result_variation == (0, False)
57-
57+
5858
def test_bucket_by_user_key(self):
5959
user = Context.create('userKeyA')
6060
bucket = _bucket_context(None, user, None, 'hashKey', 'saltyA', None)

testing/impl/test_evaluator_clause.py ldclient/testing/impl/test_evaluator_clause.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
from ldclient.client import Context
2-
from testing.builders import *
3-
from testing.impl.evaluator_util import *
2+
from ldclient.testing.builders import *
3+
from ldclient.testing.impl.evaluator_util import *
44

55

66
def assert_match_clause(clause: dict, context: Context, should_match: bool):

testing/impl/test_evaluator_prerequisites.py ldclient/testing/impl/test_evaluator_prerequisites.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44
from ldclient.evaluation import EvaluationDetail
55
from ldclient.impl.events.types import EventInputEvaluation
66

7-
from testing.builders import *
8-
from testing.impl.evaluator_util import *
7+
from ldclient.testing.builders import *
8+
from ldclient.testing.impl.evaluator_util import *
99

1010

1111
def test_flag_returns_off_variation_if_prerequisite_not_found():

testing/impl/test_evaluator_segment.py ldclient/testing/impl/test_evaluator_segment.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22

33
from ldclient import Context
44
from ldclient.impl.evaluator import _bucket_context
5-
from testing.builders import *
6-
from testing.impl.evaluator_util import *
5+
from ldclient.testing.builders import *
6+
from ldclient.testing.impl.evaluator_util import *
77

88

99
def _segment_matches_context(segment: Segment, context: Context) -> bool:

testing/impl/test_evaluator_target.py ldclient/testing/impl/test_evaluator_target.py

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
from ldclient.client import Context
2-
from testing.builders import *
3-
from testing.impl.evaluator_util import *
2+
from ldclient.testing.builders import *
3+
from ldclient.testing.impl.evaluator_util import *
44

55

66
FALLTHROUGH_VAR = 0
@@ -34,7 +34,7 @@ def test_user_targets_only(self):
3434
.target(MATCH_VAR_1, 'c') \
3535
.target(MATCH_VAR_2, 'b', 'a') \
3636
.build()
37-
37+
3838
expect_match(flag, Context.create('a'), MATCH_VAR_2)
3939
expect_match(flag, Context.create('b'), MATCH_VAR_2)
4040
expect_match(flag, Context.create('c'), MATCH_VAR_1)
@@ -61,7 +61,7 @@ def test_user_targets_and_context_targets(self):
6161
.context_target(Context.DEFAULT_KIND, MATCH_VAR_1) \
6262
.context_target(Context.DEFAULT_KIND, MATCH_VAR_2) \
6363
.build()
64-
64+
6565
expect_match(flag, Context.create('a'), MATCH_VAR_2)
6666
expect_match(flag, Context.create('b'), MATCH_VAR_2)
6767
expect_match(flag, Context.create('c'), MATCH_VAR_1)

testing/impl/test_flag_tracker.py ldclient/testing/impl/test_flag_tracker.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
from ldclient.impl.flag_tracker import FlagTrackerImpl
2-
from testing.test_util import SpyListener
2+
from ldclient.testing.test_util import SpyListener
33
from ldclient.impl.listeners import Listeners
44
from ldclient.interfaces import FlagChange
55

File renamed without changes.
File renamed without changes.

testing/impl/test_model_decode.py ldclient/testing/impl/test_model_decode.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
from ldclient.impl.model import *
66

7-
from testing.builders import *
7+
from ldclient.testing.builders import *
88

99

1010
def test_flag_targets_are_stored_as_sets():
File renamed without changes.

testing/impl/test_operators.py ldclient/testing/impl/test_operators.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
from ldclient.impl import operators
44

5-
from testing.builders import *
5+
from ldclient.testing.builders import *
66

77

88
@pytest.mark.parametrize("op,context_value,clause_value,expected", [
File renamed without changes.
File renamed without changes.

testing/integrations/persistent_feature_store_test_base.py ldclient/testing/integrations/persistent_feature_store_test_base.py

+6-6
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,12 @@
55
from ldclient.interfaces import FeatureStore
66
from ldclient.versioned_data_kind import FEATURES
77

8-
from testing.feature_store_test_base import FeatureStoreTestBase, FeatureStoreTester, StoreTestScope
9-
from testing.test_util import skip_database_tests
8+
from ldclient.testing.feature_store_test_base import FeatureStoreTestBase, FeatureStoreTester, StoreTestScope
9+
from ldclient.testing.test_util import skip_database_tests
1010

1111

1212
# The standard test suite to be run against all persistent feature store implementations. See
13-
# testing.feature_store_test_base for the basic model being used here. For each database integration,
13+
# ldclient.testing.feature_store_test_base for the basic model being used here. For each database integration,
1414
# we must define a subclass of PersistentFeatureStoreTester which overrides its abstract methods as
1515
# appropriate for that database, and then define a subclass of PersistentFeatureStoreTestBase which
1616
# simply specifies what tester subclass to use.
@@ -29,7 +29,7 @@ def create_persistent_feature_store(self, prefix: str, caching: CacheConfig) ->
2929
:param caching: caching parameters for the store constructor
3030
"""
3131
pass
32-
32+
3333
@abstractmethod
3434
def clear_data(self, prefix: str):
3535
"""
@@ -74,12 +74,12 @@ def test_stores_with_different_prefixes_are_independent(self):
7474
tester_b = self.tester_class()
7575
tester_b.prefix = "b"
7676
tester_b.clear_data(tester_b.prefix)
77-
77+
7878
flag_a1 = { 'key': 'flagA1', 'version': 1 }
7979
flag_a2 = { 'key': 'flagA2', 'version': 1 }
8080
flag_b1 = { 'key': 'flagB1', 'version': 1 }
8181
flag_b2 = { 'key': 'flagB2', 'version': 1 }
82-
82+
8383
with StoreTestScope(tester_a.create_feature_store()) as store_a:
8484
with StoreTestScope(tester_b.create_feature_store()) as store_b:
8585
store_a.init({ FEATURES: { 'flagA1': flag_a1 } })

0 commit comments

Comments
 (0)