Skip to content

Commit 4f0065a

Browse files
authored
Merge pull request #109 from reddit/update_docs_w_version
Bump Decider (re-enable `PartialLoad` error), update version in docs + tests
2 parents dd9cbc6 + 72e9bd2 commit 4f0065a

File tree

6 files changed

+109
-6
lines changed

6 files changed

+109
-6
lines changed

docs/index.rst

+4-2
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,9 @@ Setup :code:`reddit-experiments` in your application's configuration file:
4343
experiments.path = /var/local/foo.json
4444
4545
# optional: how long to wait for the experiments file to exist before failing
46-
# (default: do not wait. fail immediately if not available)
46+
# default:
47+
# >= v1.7.0 wait 30 seconds
48+
# < v1.7.0 do not wait, fail immediately if not available
4749
experiments.timeout = 60 seconds
4850
4951
# optional: the base amount of time for exponential backoff while waiting
@@ -62,7 +64,7 @@ Upgrade or integrate reddit-experiments package:
6264
.. code-block:: python
6365
6466
# import latest reddit-experiments package in service requirements.txt
65-
reddit-experiments>=1.4.0
67+
reddit-experiments>=1.7.0
6668
6769
Initialize :code:`decider` instance on Baseplate context
6870
--------------------------------------------------------

docs/requirements.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ docutils==0.16
44
Jinja2==2.11.2
55
MarkupSafe==1.1.1
66
pydocstyle==5.1.1
7-
reddit-decider==1.3.1
7+
reddit-decider==1.4.1
88
reddit-edgecontext==1.0.0a3
99
Sphinx==3.4.0
1010
sphinx-autodoc-typehints==1.11.1

requirements.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
-r requirements-transitive.txt
22
baseplate>=2.0.0a1,<3.0
33
black==21.4b2
4-
reddit-decider==1.3.1
4+
reddit-decider==1.4.1
55
flake8==3.9.1
66
mypy==0.790
77
pyramid==2.0 # required for `from baseplate.frameworks.pyramid import BaseplateRequest` which calls `import pyramid.events`

setup.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
install_requires=[
2020
"baseplate>=2.0.0a1,<3.0",
2121
"reddit-edgecontext>=1.0.0a3,<2.0",
22-
"reddit-decider~=1.3.1",
22+
"reddit-decider~=1.4.1",
2323
"typing_extensions>=3.10.0.0,<5.0",
2424
],
2525
package_data={"reddit_experiments": ["py.typed"], "reddit_decider": ["py.typed"]},

tests/decider_tests.py

+66-1
Original file line numberDiff line numberDiff line change
@@ -497,7 +497,7 @@ def test_none_returned_on_get_variant_call_with_bad_id(self):
497497
self.assertEqual(self.event_logger.log.call_count, 0)
498498

499499
assert any(
500-
"Partially loaded Decider: 1 features failed to load: {'test': 'invalid type: string \"1\", expected u32'}"
500+
"Partially loaded Decider: 1 features failed to load: {'test': 'Manifest parsing error: invalid type: string \"1\", expected u32'}"
501501
in x.getMessage()
502502
for x in captured.records
503503
)
@@ -1481,6 +1481,59 @@ def test_get_variant_without_expose_with_HG_as_control_1_and_child_returns_none_
14811481
experiment_name="hg", variant="control_1", event_fields=event_fields
14821482
)
14831483

1484+
def test_get_variant_for_okta_groups(self):
1485+
identifier = "t2_test"
1486+
bucket_val = "user_id"
1487+
group_overrides = {"variant_2": {"EQ": {"field": "user_id", "values": ["$some_group_id"]}}}
1488+
1489+
self.exp_base_config["exp_1"]["experiment"].update({"overrides": [group_overrides]})
1490+
# reset variant for override to make sure it's not organically bucketed into it
1491+
self.exp_base_config["exp_1"]["experiment"].update(
1492+
{
1493+
"variants": [
1494+
{"range_start": 0.0, "range_end": 0.0, "name": "variant_2"},
1495+
]
1496+
}
1497+
)
1498+
1499+
og_cfg = {
1500+
"$override_groups": {
1501+
"id": 1337,
1502+
"value": {
1503+
"$some_group_id": {
1504+
"name": "some_group_id",
1505+
"values": [identifier],
1506+
"field": "user_id",
1507+
}
1508+
},
1509+
"type": "dynamic_config",
1510+
"version": "1",
1511+
"enabled": False,
1512+
"owner": "test",
1513+
"name": "$override_group",
1514+
"value_type": "Map",
1515+
"experiment": {"experiment_version": 1},
1516+
},
1517+
}
1518+
self.exp_base_config.update(og_cfg)
1519+
1520+
with create_temp_config_file(self.exp_base_config) as f:
1521+
decider = setup_decider(f, self.dc, self.mock_span, self.event_logger)
1522+
1523+
self.assertEqual(self.event_logger.log.call_count, 0)
1524+
variant = decider.get_variant_for_identifier_without_expose(
1525+
experiment_name="exp_1", identifier=identifier, identifier_type=bucket_val
1526+
)
1527+
self.assertEqual(variant, "variant_2")
1528+
1529+
self.dc._user_id = identifier
1530+
decider = setup_decider(f, self.dc, self.mock_span, self.event_logger)
1531+
variant = decider.get_variant_without_expose(experiment_name="exp_1")
1532+
self.assertEqual(variant, "variant_2")
1533+
1534+
# no exposures should be triggered
1535+
self.assertEqual(self.event_logger.log.call_count, 0)
1536+
14841537

14851538
class TestDeciderGetDynamicConfig(unittest.TestCase):
14861539
def setUp(self):
@@ -1574,6 +1627,18 @@ def test_get_map(self):
15741627
res = decider.get_string("dc_1")
15751628
self.assertEqual(res, "")
15761629

1630+
def test_get_map_disabled(self):
1631+
self.dc_base_config["dc_1"].update(
1632+
{"value_type": "Map", "value": {"key": "value", "another_key": "another_value"}}
1633+
)
1634+
self.dc_base_config["dc_1"].update({"enabled": False})
1635+
1636+
with create_temp_config_file(self.dc_base_config) as f:
1637+
decider = setup_decider(f, self.dc, self.mock_span, self.event_logger)
1638+
1639+
res = decider.get_map("dc_1")
1640+
self.assertEqual(res, None)
1641+
15771642
def test_get_all_values(self):
15781643
base_cfg = self.dc_base_config["dc_1"].copy()
15791644

tests/experiment_tests.py

+36
Original file line numberDiff line numberDiff line change
@@ -674,6 +674,42 @@ def test_none_returned_on_variant_call_with_no_experiment_with_cfg_data(self):
674674
variant = experiments.variant("test", user=self.user)
675675
self.assertEqual(variant, None)
676676

677+
def test_new_identifier_compatibility(self):
678+
self.mock_filewatcher.get_data.return_value = {
679+
"test": {
680+
"id": 1,
681+
"name": "test",
682+
"enabled": True,
683+
"owner": "test_owner",
684+
"version": "1",
685+
"emit_event": True,
686+
"type": "range_variant",
687+
"start_ts": time.time() - THIRTY_DAYS,
688+
"stop_ts": time.time() + THIRTY_DAYS,
689+
"experiment": {
690+
"variants": [
691+
{"name": "active", "size": 1, "range_end": 1.0, "range_start": 0},
692+
],
693+
"experiment_version": 5,
694+
"shuffle_version": 91,
695+
"bucket_val": "ad_account_id",
696+
"log_bucketing": False,
697+
},
698+
}
699+
}
700+
701+
experiments = Experiments(
702+
config_watcher=self.mock_filewatcher,
703+
server_span=self.mock_span,
704+
context_name="test",
705+
event_logger=self.event_logger,
706+
)
707+
708+
self.assertEqual(self.event_logger.log.call_count, 0)
709+
variant = experiments.variant("test", ad_account_id="a2_xxx")
710+
711+
self.assertEqual(variant, "active")
712+
677713

678714
@mock.patch("reddit_experiments.FileWatcher")
679715
class ExperimentsClientFromConfigTests(unittest.TestCase):

0 commit comments

Comments
 (0)