"""Tests of killswitch behaviour.""" from __future__ import annotations import copy import pytest import semantic_version import killswitch TEST_SET = killswitch.KillSwitchSet([ killswitch.KillSwitches( version=semantic_version.SimpleSpec('1.0.0'), kills={ 'no-actions': killswitch.SingleKill('no-actions', 'test'), 'delete-action': killswitch.SingleKill('delete-action', 'remove stuff', delete_fields=['a', 'b.c']), 'delete-action-l': killswitch.SingleKill('delete-action-l', 'remove stuff', delete_fields=['2', '0']), 'set-action': killswitch.SingleKill('set-action', 'set stuff', set_fields={'a': False, 'b.c': True}), 'redact-action': killswitch.SingleKill('redact-action', 'redact stuff', redact_fields=['a', 'b.c']) } ) ]) @pytest.mark.parametrize( ('input', 'kill', 'should_pass', 'result', 'version'), [ ([], 'doesnt-exist', True, None, '1.0.0'), # should fail, attempts to use 'a' to index a list (['a', 'b', 'c'], 'delete-action', False, ['a', 'b', 'c'], '1.0.0'), (['a', 'b', 'c'], 'delete-action-l', True, ['b'], '1.0.0'), (set(), 'delete-action-l', False, None, '1.0.0'), # set should be thrown out because it cant be indext (['a', 'b'], 'delete-action-l', True, ['b'], '1.0.0'), # has a missing value, but that's fine for delete (['a', 'b'], 'delete-action-l', True, ['a', 'b'], '1.1.0'), # wrong version ], ) def test_killswitch( input: killswitch.UPDATABLE_DATA, kill: str, should_pass: bool, result: killswitch.UPDATABLE_DATA | None, version: str ) -> None: """Simple killswitch tests.""" should_return, res = TEST_SET.check_killswitch(kill, input, version=version) assert (not should_return) == should_pass, ( f'expected to {"pass" if should_pass else "fail"}, but {"passed" if not should_pass else "failed"}' ) if result is None: return # we didn't expect any result assert res == result @pytest.mark.parametrize( ('kill_dict', 'input', 'result'), [ ({'set_fields': {'test': None}}, {}, {'test': None}), ({'set_fields': {'test': None}, 'delete_fields': ['test']}, {}, {}), ({'set_fields': {'test': None}, 'redact_fields': ['test']}, {}, {'test': 'REDACTED'}), ({'set_fields': {'test': None}, 'redact_fields': ['test'], 'delete_fields': ['test']}, {}, {}), ], ) def test_operator_precedence( kill_dict: killswitch.SingleKillSwitchJSON, input: killswitch.UPDATABLE_DATA, result: killswitch.UPDATABLE_DATA ) -> None: """Ensure that operators are being applied in the correct order.""" kill = killswitch.SingleKill( "", "", kill_dict.get('redact_fields'), kill_dict.get('delete_fields'), kill_dict.get('set_fields') ) cpy = copy.deepcopy(input) kill.apply_rules(cpy) assert cpy == result @pytest.mark.parametrize( ('names', 'input', 'result', 'expected_return'), [ (['no-actions', 'delete-action'], {'a': 1}, {'a': 1}, True), # this is true because delete-action keyerrors, thus causing failsafe (['delete-action'], {'a': 1}, {'a': 1}, True), (['delete-action'], {'a': 1, 'b': {'c': 2}}, {'b': {}}, False), ] ) def test_check_multiple( names: list[str], input: killswitch.UPDATABLE_DATA, result: killswitch.UPDATABLE_DATA, expected_return: bool ) -> None: """Check that order is correct when checking multiple killswitches.""" should_return, data = TEST_SET.check_multiple_killswitches(input, *names, version='1.0.0') assert should_return == expected_return assert data == result