Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixes #2944, #2947 - Read experiment variation values from envvars #2951

Merged
merged 1 commit into from
Oct 10, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 41 additions & 3 deletions config/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,29 @@ def update_status_config(milestones_content):
return STATUSES


def get_variation(variation_key, variations_dict, defaults_dict):
"""Convert a string to a tuple of integers.
miketaylr marked this conversation as resolved.
Show resolved Hide resolved

If the passed variation_key doesn't follow this pattern '0 100', it will
return default values defined in defaults_dict.

This is currently used for defining the variation data of the A/B
experiment regarding the multi-steps form.
"""
try:
# We want to create a tuple of integers from a string containing
# integers. Anything else should throw.
rv = tuple(int(x) for x in variations_dict.get(variation_key)
.strip().split())
if (len(rv) != 2):
raise ValueError('The format is incorrect. Expected "{int} {int}"')
except Exception as e:
miketaylr marked this conversation as resolved.
Show resolved Hide resolved
print('Something went wrong with AB test configuration: {0}'.format(e))
print('Falling back to default values.')
rv = defaults_dict.get(variation_key)
return rv


THREADS_PER_PAGE = 8

# ~3 months-ish expires for static junk
Expand Down Expand Up @@ -200,14 +223,29 @@ def update_status_config(milestones_content):
'type-webvr',
]

# Get AB experiment variation values from the environement.
AB_VARIATIONS = {
'FORM_V1_VARIATION': os.environ.get('FORM_V1_VARIATION'),
'FORM_V2_VARIATION': os.environ.get('FORM_V2_VARIATION'),
}
# We define default values here, as a fallback.
# By default, v1 will be served 100% of the time.
AB_DEFAULTS = {
'FORM_V1_VARIATION': (0, 100),
'FORM_V2_VARIATION': (100, 100),
}
EXP_MAX_AGE = int(os.environ.get('EXP_MAX_AGE', 0))

# AB testing config
AB_EXPERIMENTS = {
'exp': {
'variations': {
'form-v1': (0, 100),
'form-v2': (100, 100)
'form-v1': get_variation('FORM_V1_VARIATION', AB_VARIATIONS,
AB_DEFAULTS),
'form-v2': get_variation('FORM_V2_VARIATION', AB_VARIATIONS,
AB_DEFAULTS),
},
'max-age': None
'max-age': EXP_MAX_AGE
}
}

Expand Down
17 changes: 15 additions & 2 deletions docs/ab-testing.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,23 @@
# AB testing
## Configuration
You can enable/disable AB testing support by configuring the `config.AB_EXPERIMENT` dictionary.
This will configure flask to set cookies to responses. For example:
You can enable/disable AB testing support by configuring the following environment variables:

`FORM_V1_VARIATION`: expects a string of the format '{int} {int}'
`FORM_V2_VARIATION`: expects a string of the format '{int} {int}'
`EXP_MAX_AGE`: expects a number which defines when the experiment cookie expires

These are read by the `config.AB_EXPERIMENT` dictionary in `./config/__init__.py` and converted to a tuple.
This will configure flask to set cookies to responses. For example, setting the variables to the following:

```
export FORM_V1_VARIATION = "0 20"
export FORM_V2_VARIATION = "20 100"
miketaylr marked this conversation as resolved.
Show resolved Hide resolved
export EXP_MAX_AGE = 604800
```

This will result in the `AB_EXPERIMENTS` dictionary with the following values:

```
AB_EXPERIMENTS = {
'exp-1': {
'variations': {
Expand Down
15 changes: 15 additions & 0 deletions tests/unit/test_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import unittest

from config import update_status_config
from config import get_variation
from webcompat import webcompat


Expand Down Expand Up @@ -53,6 +54,20 @@ def test_update_status_config(self):
actual = update_status_config(milestones_json)
self.assertEqual(actual, expected)

def test_get_variation(self):
"""
Check the conversion from string to tuples of two int.
"""
defs = {'a': (1, 2)}
self.assertTupleEqual((1, 2), get_variation('a', {'a': '1 2'}, defs))
self.assertTupleEqual((1, 2), get_variation('a', {'a': None}, defs))
self.assertTupleEqual((1, 2), get_variation('a', {'a': ''}, defs))
self.assertTupleEqual((1, 2), get_variation('a', {'a': 2}, defs))
self.assertTupleEqual((1, 2), get_variation('a', {'a': '1 2 3'}, defs))
self.assertTupleEqual((1, 2), get_variation('a', {'a': '1 '}, defs))
self.assertTupleEqual((1, 2),
get_variation('a', {'a': ' 1 2 '}, defs))


if __name__ == '__main__':
unittest.main()