Пример #1
0
async def test_flags_setting_validator(fake_heksher_service, monkeypatch):
    monkeypatch.setattr(fake_heksher_service, 'context_features',
                        ['a', 'b', 'c'])
    monkeypatch.setitem(fake_heksher_service.declare_responses, 'c',
                        {'outcome': 'created'})

    class Color(IntFlag):
        blue = auto()
        red = auto()
        green = auto()

    c = Setting('c', Color, 'abc', default_value=Color(0))

    @c.add_validator
    def add_red(value, *_):
        return value | Color.red

    with fake_heksher_service.query_rules.patch(
            JSONResponse({
                'settings': {
                    'c': {
                        'rules': [{
                            'context_features': [['a', 'x']],
                            'value': ['green', 'blue'],
                            'rule_id': 1
                        }],
                        'default_value': []
                    }
                }
            })):
        async with AsyncHeksherClient(fake_heksher_service.local_url(), 1000,
                                      ['a', 'b', 'c']):
            assert c.get(a='x', b='',
                         c='') == Color.green | Color.blue | Color.red
            assert c.get(a='y', b='', c='') == Color.red
Пример #2
0
def apply_difference(setting: Setting, difference: Mapping[str, Any]) -> None:
    attr = difference.get('attribute')
    # right now we only know how to handle the 'default_value' attribute difference
    if attr == 'default_value':
        server_default_value = difference.get('latest_value')
        try:
            convert = setting.convert_server_value(server_default_value, None)
        except TypeError:
            logger.warning(
                'server default was discarded due to coercion error during declaration',
                exc_info=True,
                extra={
                    'setting_name': setting.name,
                    'server_default_value': server_default_value
                })
        else:
            if convert.coercions:
                logger.warning(
                    'server default was coerced to local value during declaration',
                    extra={
                        'setting_name': setting.name,
                        'server_default_value': server_default_value,
                        'coercions': convert.coercions
                    })
            setting.server_default_value = convert.value
Пример #3
0
async def test_trackcontexts(fake_heksher_service, monkeypatch):
    monkeypatch.setattr(fake_heksher_service, 'context_features',
                        ['a', 'b', 'c', 'd'])
    monkeypatch.setitem(fake_heksher_service.declare_responses, 'cache_size',
                        {'outcome': 'created'})

    setting = Setting('cache_size', int, ['b', 'c'], 50)
    with fake_heksher_service.query_rules.patch(
            JSONResponse({
                'settings': {
                    'cache_size': {
                        'rules': [{
                            'context_features': [['b', 'B']],
                            'value': 100,
                            'rule_id': 1
                        }],
                        'default_value':
                        100
                    }
                }
            })), fake_heksher_service.query_rules.capture_calls(
            ) as query_calls:
        client = AsyncHeksherClient(fake_heksher_service.local_url(), 100000,
                                    ['a', 'b', 'c', 'd'])
        client.track_contexts(b='B', a=['a0', 'a1'], d=TRACK_ALL)

        async with client:
            assert setting.get(b='B', c='') == 100

    query_calls.assert_requested_once_with(
        query_params={
            'settings': ['cache_size'],
            'context_filters': ['a:(a0,a1),b:(B),d:*'],
            'include_metadata': ['false']
        })
Пример #4
0
async def test_flags_setting_reject_default(fake_heksher_service, monkeypatch,
                                            caplog):
    monkeypatch.setattr(fake_heksher_service, 'context_features',
                        ['a', 'b', 'c'])
    monkeypatch.setitem(fake_heksher_service.declare_responses, 'c',
                        {'outcome': 'created'})

    class Color(IntFlag):
        blue = auto()
        red = auto()
        green = auto()

    c = Setting('c', Color, 'abc', default_value=Color(0))
    with fake_heksher_service.query_rules.patch(
            JSONResponse({
                'settings': {
                    'c': {
                        'rules': [{
                            'context_features': [['a', 'f']],
                            'value': ['green', 'blue'],
                            'rule_id': 1
                        }],
                        'default_value': [['blank']]
                    }
                }
            })):
        caplog.clear()
        with assert_logs(caplog, WARNING):
            async with AsyncHeksherClient(fake_heksher_service.local_url(),
                                          1000, ['a', 'b', 'c']):
                assert c.get(a='re', b='', c='') == Color(0)
Пример #5
0
async def test_declare_after_main(fake_heksher_service, monkeypatch):
    monkeypatch.setattr(fake_heksher_service, 'context_features',
                        ['a', 'b', 'c'])
    monkeypatch.setitem(fake_heksher_service.declare_responses, 'cache_size',
                        {'outcome': 'created'})

    async with AsyncHeksherClient(fake_heksher_service.local_url(), 10000000,
                                  ['a', 'b', 'c']) as client:
        setting = Setting('cache_size', int, ['b', 'c'], 50)
        assert not client._undeclared.empty()
        await client._undeclared.join()
        assert setting.get(b='', c='') == 50

        with fake_heksher_service.query_rules.patch(
                JSONResponse({
                    'settings': {
                        'cache_size': {
                            'rules': [{
                                'context_features': [],
                                'value': 100,
                                'rule_id': 1
                            }],
                            'default_value':
                            100
                        }
                    }
                })):
            await client.reload()
            assert setting.get(b='', c='') == 100
Пример #6
0
async def test_regular_update(fake_heksher_service, monkeypatch):
    monkeypatch.setattr(fake_heksher_service, 'context_features',
                        ['a', 'b', 'c'])
    monkeypatch.setitem(fake_heksher_service.declare_responses, 'cache_size',
                        {'outcome': 'created'})

    setting = Setting('cache_size', int, ['b', 'c'], 50)

    async with AsyncHeksherClient(fake_heksher_service.local_url(), 0.02,
                                  ['a', 'b', 'c']):
        assert setting.get(b='', c='') == 50
        with fake_heksher_service.query_rules.patch(
                JSONResponse({
                    'settings': {
                        'cache_size': {
                            'rules': [{
                                'context_features': [],
                                'value': 100,
                                'rule_id': 1
                            }],
                            'default_value':
                            100
                        }
                    }
                })):
            await sleep(1)
            assert setting.get(b='', c='') == 100
Пример #7
0
async def test_redundant_defaults(fake_heksher_service, caplog, monkeypatch):
    monkeypatch.setattr(fake_heksher_service, 'context_features',
                        ['a', 'b', 'c'])
    monkeypatch.setitem(fake_heksher_service.declare_responses, 'cache_size',
                        {'outcome': 'created'})

    setting = Setting('cache_size', int, ['b', 'c'], 50)
    with fake_heksher_service.query_rules.patch(
            JSONResponse({
                'settings': {
                    'cache_size': {
                        'rules': [{
                            'context_features': [['b', 'B']],
                            'value': 100,
                            'rule_id': 1
                        }],
                        'default_value':
                        100
                    }
                }
            })):
        with assert_logs(caplog, WARNING):
            async with AsyncHeksherClient(fake_heksher_service.local_url(),
                                          1000, ['a', 'b', 'c']) as client:
                client.set_defaults(b='B', d='im redundant')
                assert setting.get(c='') == 100
Пример #8
0
async def test_heksher_unreachable(caplog):
    setting = Setting('cache_size', int, ['b', 'c'], 50)
    caplog.clear()
    with assert_logs(caplog, ERROR), raises(HTTPError):
        async with AsyncHeksherClient('http://notreal.fake.notreal', 10000000,
                                      ['a', 'b', 'c']):
            pass
    assert setting.get(b='', c='') == 50
Пример #9
0
def test_heksher_unreachable(caplog):
    setting = Setting('cache_size', int, ['b', 'c'], 50)

    with assert_logs(caplog, ERROR):
        with ThreadHeksherClient('http://notreal.fake.notreal', 10000,
                                 ['a', 'b', 'c']):
            pass
    assert setting.get(b='', c='') == 50
Пример #10
0
def test_v1_body():
    a = Setting('aaa', int, 'abcx', default_value=-1, metadata={"some": "thing"}, alias='aaaa', version='3.6')
    assert a.to_v1_declaration_body() == {
        'name': 'aaa',
        'configurable_features': list('abcx'),
        'type': 'int',
        'metadata': {"some": "thing"},
        'alias': 'aaaa',
        'default_value': -1,
        'version': '3.6',
    }
Пример #11
0
def test_switch_main_unclosed(fake_heksher_service, monkeypatch):
    monkeypatch.setattr(fake_heksher_service, 'context_features', ['a', 'b'])
    monkeypatch.setitem(fake_heksher_service.declare_responses, 'conf1',
                        {'outcome': 'created'})
    monkeypatch.setitem(fake_heksher_service.declare_responses, 'conf2',
                        {'outcome': 'created'})
    monkeypatch.setitem(fake_heksher_service.declare_responses, 'conf3',
                        {'outcome': 'created'})
    setting1 = Setting('conf1', int, ['a'], 74)
    client1 = ThreadHeksherClient(fake_heksher_service.local_url(), 10000000,
                                  ['a', 'b'])
    client1.track_contexts(a=['a', 'b'], b=TRACK_ALL)
    client1.set_as_main()
    client1.close()
    setting2 = Setting('conf2', int, ['b'], 26)
    client2 = ThreadHeksherClient(fake_heksher_service.local_url(), 10000000,
                                  ['a', 'b'])
    client2.track_contexts(a=['a', 'b'], b=TRACK_ALL)
    with raises(RuntimeError):  # not allowed
        client2.set_as_main()
Пример #12
0
def test_multi_switch(caplog):
    a = Setting('a', int, 'abcx', default_value=-1)
    c1 = SyncStubHeksherClient()
    c1.set_defaults(a='', b='', c='')
    c1.set_as_main()
    c1.patch(a, 10)
    assert a.get(x='') == 10
    heksher.main_client.Main = TemporaryClient()

    c2 = SyncStubHeksherClient()
    c2.set_defaults(a='', b='', c='')
    c2.set_as_main()
    with assert_logs(caplog, WARNING):
        c2.patch(a, [
            Rule({'x': '0'}, 0),
            Rule({'x': '1'}, 1)
        ])
    assert a.get(x='0') == 0
    assert a.get(x='1') == 1
    assert a.get(x='15') == -1
Пример #13
0
def test_setting_callback_stub():
    # stubs don't trigger conversion
    a = Setting('a', int, 'abcx', default_value=-1)

    def setting_callback_1(value: int, rule, setting: Setting) -> int:
        if setting.name == 'a' and value == 10:
            return 12
        return value

    def setting_callback_2(value: int, rule, setting: Setting) -> int:
        if setting.name == 'a' and value == 12:
            return 7
        return value

    a.add_validator(setting_callback_1)
    a.add_validator(setting_callback_2)
    c1 = SyncStubHeksherClient()
    c1.set_as_main()
    c1.set_defaults(a='', b='', c='', x='')
    c1.patch(a, 10)
    assert a.get() == 10
Пример #14
0
def test_nested_update():
    a = Setting('a', int, 'abcx', default_value=-1)
    with SyncStubHeksherClient() as client:
        client.set_defaults(a='', b='', c='', x='')
        assert a.get() == -1
        with client.patch(a, 0):
            assert a.get() == 0
            with client.patch(a, 1):
                assert a.get() == 1
            assert a.get() == 0
        assert a.get() == -1
Пример #15
0
async def test_upgraded_declaration_different_default(fake_heksher_service,
                                                      monkeypatch, caplog):
    monkeypatch.setattr(fake_heksher_service, 'context_features',
                        ['a', 'b', 'c'])
    monkeypatch.setitem(
        fake_heksher_service.declare_responses, 'cache_size', {
            'outcome':
            'upgraded',
            'latest_version':
            '0.5',
            'differences': [{
                'level': 'minor',
                'attribute': 'default_value',
                'latest_value': 100
            }]
        })

    setting = Setting('cache_size', int, ['b', 'c'], 50)

    async with AsyncHeksherClient(fake_heksher_service.local_url(), 10000000,
                                  ['a', 'b', 'c']):
        assert setting.get(b='', c='') == 50
Пример #16
0
def test_setting_rules_collection_callback():
    a = Setting('a', int, 'abcx', default_value=-1)

    def setting_callback_1(value: int, rule, setting: Setting) -> int:
        if setting.name == 'a' and value == 0:
            return 3
        return value

    def setting_callback_2(value: int, rule, setting: Setting) -> int:
        if setting.name == 'a' and value == 3:
            return 7
        return value

    a.add_validator(setting_callback_1)
    a.add_validator(setting_callback_2)
    c1 = SyncStubHeksherClient()
    c1.set_as_main()
    c1.set_defaults(a='', b='', c='', x='')

    c1.patch(a, [
        Rule({'x': '0'}, 0)
    ])
    assert a.get(x='0') == 0
    assert a.get(x='1') == -1
Пример #17
0
def test_declare_before_main(fake_heksher_service, monkeypatch):
    monkeypatch.setattr(fake_heksher_service, 'context_features',
                        ['a', 'b', 'c'])
    monkeypatch.setitem(fake_heksher_service.declare_responses, 'cache_size',
                        {'outcome': 'created'})

    setting = Setting('cache_size', int, ['b', 'c'], 50)
    with fake_heksher_service.query_rules.patch(
            JSONResponse({
                'settings': {
                    'cache_size': {
                        'rules': [{
                            'context_features': [],
                            'value': 100,
                            'rule_id': 1
                        }],
                        'default_value':
                        100
                    }
                }
            })):
        with ThreadHeksherClient(fake_heksher_service.local_url(), 100000,
                                 ['a', 'b', 'c']):
            assert setting.get(b='', c='') == 100
Пример #18
0
async def test_outdated_declaration(fake_heksher_service, monkeypatch, caplog):
    monkeypatch.setattr(fake_heksher_service, 'context_features',
                        ['a', 'b', 'c'])
    monkeypatch.setitem(fake_heksher_service.declare_responses, 'cache_size', {
        'outcome': 'outdated',
        'latest_version': '2.0',
        'differences': []
    })

    setting = Setting('cache_size', int, ['b', 'c'], 50)

    with assert_logs(caplog, WARNING):
        async with AsyncHeksherClient(fake_heksher_service.local_url(),
                                      10000000, ['a', 'b', 'c']):
            pass
Пример #19
0
def test_resolve():
    a = Setting('a', int, 'abcx', default_value=-1)
    with SyncStubHeksherClient() as client, \
            client.patch(a, [
                Rule({'x': '0'}, 0),
                Rule({'x': '1'}, 1)
            ]):
        client.set_defaults(a='', b='', c='')
        assert a.get(x='0') == 0
        assert a.get(x='1') == 1
        assert a.get(x='15') == -1
        with raises(RuntimeError):
            a.get()

        client.set_defaults(x='0')
        assert a.get(x='1') == 1
Пример #20
0
async def test_switch_main_different_contexts(fake_heksher_service,
                                              monkeypatch):
    monkeypatch.setattr(fake_heksher_service, 'context_features',
                        ['a', 'b', 'c'])
    monkeypatch.setitem(fake_heksher_service.declare_responses, 'conf1',
                        {'outcome': 'created'})
    monkeypatch.setitem(fake_heksher_service.declare_responses, 'conf2',
                        {'outcome': 'created'})
    monkeypatch.setitem(fake_heksher_service.declare_responses, 'conf3',
                        {'outcome': 'created'})
    setting1 = Setting('conf1', int, ['a'], 74)
    client1 = AsyncHeksherClient(fake_heksher_service.local_url(), 10000000,
                                 ['a', 'b'])
    client1.track_contexts(a=['a', 'b'], b=TRACK_ALL)
    await client1.set_as_main()
    setting2 = Setting('conf2', int, ['b'], 26)
    with fake_heksher_service.query_rules.patch(
            JSONResponse({
                'settings': {
                    'conf1': {
                        'rules': [{
                            'context_features': [],
                            'value': 5,
                            'rule_id': 1
                        }],
                        'default_value':
                        74
                    },
                    'conf2': {
                        'rules': [{
                            'context_features': [],
                            'value': 4,
                            'rule_id': 2
                        }],
                        'default_value':
                        26
                    }
                }
            })):
        await client1.reload()
        assert len(client1._tracked_settings) == 2
        assert setting1.get(a='') == 5
        assert setting2.get(b='') == 4
    client2 = AsyncHeksherClient(fake_heksher_service.local_url(), 10000000,
                                 ['b', 'c'])
    client2.track_contexts(a=['a', 'b'], b=TRACK_ALL)
    await client1.aclose()
    with raises(RuntimeError):  # not allowed
        await client2.set_as_main()
    await client2.aclose()
Пример #21
0
def test_multi_update():
    a = Setting('a', int, 'abcx', default_value=-1)
    with SyncStubHeksherClient() as client:
        client.set_defaults(a='', b='', c='')
        client.patch(a, 10)
        assert a.get(x='') == 10
        with client.patch(a, [
            Rule({'x': '0'}, 0),
            Rule({'x': '1'}, 1)
        ]):
            assert a.get(x='0') == 0
            assert a.get(x='1') == 1
            assert a.get(x='15') == -1
        assert a.get(x='0') == 10
Пример #22
0
async def test_switch_main_from_temp(fake_heksher_service, monkeypatch):
    monkeypatch.setattr(fake_heksher_service, 'context_features', ['a', 'b'])
    monkeypatch.setitem(fake_heksher_service.declare_responses, 'conf1',
                        {'outcome': 'created'})
    monkeypatch.setitem(fake_heksher_service.declare_responses, 'conf2',
                        {'outcome': 'created'})
    setting1 = Setting('conf1', int, ['a'], 74)
    client = AsyncHeksherClient(fake_heksher_service.local_url(), 10000000,
                                ['a', 'b'])
    client.track_contexts(a=['a', 'b'], b=TRACK_ALL)
    await client.set_as_main()
    setting2 = Setting('conf2', int, ['b'], 26)
    with fake_heksher_service.query_rules.patch(
            JSONResponse({
                'settings': {
                    'conf1': {
                        'rules': [{
                            'context_features': [],
                            'value': 5,
                            'rule_id': 1
                        }],
                        'default_value':
                        74
                    },
                    'conf2': {
                        'rules': [{
                            'context_features': [],
                            'value': 4,
                            'rule_id': 2
                        }],
                        'default_value':
                        26
                    }
                }
            })):
        await client.reload()
        assert setting1.get(a='') == 5
        assert setting2.get(b='') == 4
        await client.aclose()
Пример #23
0
def test_get_from_temp(caplog):
    a = Setting('a', int, 'abc', default_value=0)
    with assert_logs(caplog, INFO):
        assert a.get() == 0
Пример #24
0
async def test_async_stub():
    a = Setting('a', int, ['user', 'theme'], default_value=0)

    async with AsyncStubHeksherClient() as client:
        b = Setting('b', Mapping[str, int], ['user', 'theme'], default_value=0)
        with client.patch(a, 10), client.patch(b, {
            't': 1,
            'z': 2
        }):
            c = Setting('c', int, ['user', 'theme'], default_value=0)
            client.patch(c, [
                Rule({}, 0),
                Rule({'theme': 'dark'}, 1),
                Rule({'user': '******', 'theme': None}, 2)
            ])

            assert a.get(user='', theme='') == 10
            assert b.get(user='', theme='') == {
                't': 1,
                'z': 2
            }
            assert c.get(user='', theme='') == 0
            assert c.get(user='', theme='dark') == 1
            assert c.get(user='******', theme='') == 2
            assert c.get(user='******', theme='dark') == 1
Пример #25
0
async def test_switch_main_different_tracking(fake_heksher_service,
                                              monkeypatch, caplog):
    monkeypatch.setattr(fake_heksher_service, 'context_features', ['a', 'b'])
    monkeypatch.setitem(fake_heksher_service.declare_responses, 'conf1',
                        {'outcome': 'created'})
    monkeypatch.setitem(fake_heksher_service.declare_responses, 'conf2',
                        {'outcome': 'created'})
    monkeypatch.setitem(fake_heksher_service.declare_responses, 'conf3',
                        {'outcome': 'created'})
    setting1 = Setting('conf1', int, ['a'], 74)
    client1 = AsyncHeksherClient(fake_heksher_service.local_url(), 10000000,
                                 ['a', 'b'])
    client1.track_contexts(a=['a', 'b'], b=TRACK_ALL)
    await client1.set_as_main()
    setting2 = Setting('conf2', int, ['b'], 26)
    with fake_heksher_service.query_rules.patch(
            JSONResponse({
                'settings': {
                    'conf1': {
                        'rules': [{
                            'context_features': [],
                            'value': 5,
                            'rule_id': 1
                        }],
                        'default_value':
                        74
                    },
                    'conf2': {
                        'rules': [{
                            'context_features': [],
                            'value': 4,
                            'rule_id': 2
                        }],
                        'default_value':
                        26
                    }
                }
            })):
        await client1.reload()
        assert len(client1._tracked_settings) == 2
        assert setting1.get(a='') == 5
        assert setting2.get(b='') == 4
        client2 = AsyncHeksherClient(fake_heksher_service.local_url(),
                                     10000000, ['a', 'b'])
        client2.track_contexts(a=['a', 'b', 'c'], b="shoobidoobi")
        await client1.aclose()
        with assert_logs(
                caplog, WARNING
        ):  # it should warn you you're doing bad things, and that your tracking differs
            await client2.set_as_main()
    setting3 = Setting('conf3', int, ['b'], 59)
    with fake_heksher_service.query_rules.patch(
            JSONResponse({
                'settings': {
                    'conf1': {
                        'rules': [{
                            'context_features': [],
                            'value': 5,
                            'rule_id': 1
                        }],
                        'default_value':
                        74,
                    },
                    'conf2': {
                        'rules': [{
                            'context_features': [],
                            'value': 4,
                            'rule_id': 2
                        }],
                        'default_value':
                        26,
                    },
                    'conf3': {
                        'rules': [{
                            'context_features': [],
                            'value': 3,
                            'rule_id': 3
                        }],
                        'default_value':
                        59,
                    }
                }
            })):
        await client2.reload()
        assert setting1.get(a='') == 5
        assert setting2.get(b='') == 4
        assert setting3.get(b='') == 3
        await client2.aclose()
Пример #26
0
def test_sync_stub_patcher(monkeypatch):
    a = Setting('a', int, ['user', 'theme'], default_value=0)

    with SyncStubHeksherClient() as client:
        b = Setting('b', Mapping[str, int], ['user', 'theme'], default_value=0)
        monkeypatch.setattr(client[a], 'rules', 10)
        monkeypatch.setattr(client[b], 'rules', {
            't': 1,
            'z': 2
        })
        c = Setting('c', int, ['user', 'theme'], default_value=0)
        monkeypatch.setattr(client[c], 'rules', [
            Rule({}, 0),
            Rule({'theme': 'dark'}, 1),
            Rule({'user': '******'}, 2)
        ])

        assert a.get(user='', theme='') == 10
        assert b.get(user='', theme='') == {
            't': 1,
            'z': 2
        }
        assert c.get(user='', theme='') == 0
        assert c.get(user='', theme='dark') == 1
        assert c.get(user='******', theme='') == 2
        assert c.get(user='******', theme='dark') == 1
Пример #27
0
def test_useless_vals():
    a = Setting('a', int, 'abcx', default_value=-1)
    with raises(ValueError):
        a.get(a='', b='', c='', x='', d='')