Skip to content
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
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -251,9 +251,9 @@ The following features are currently in development:
switcher.throttle(1000).is_on('FEATURE01')
```

#### Hybrid Mode (Coming Soon)
#### Hybrid Mode
```python
# 🚧 TODO: Force remote resolution for specific features
# Force remote resolution for specific features
switcher.remote().is_on('FEATURE01')
```

Expand Down
6 changes: 4 additions & 2 deletions switcher_client/switcher.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,9 @@ def _init_worker(self, context: Context):
def prepare(self, key: Optional[str] = None):
""" Checks API credentials and connectivity """
self._validate_args(key)
RemoteAuth.auth()

if not self._context.options.local or self._force_remote:
RemoteAuth.auth()

def is_on(self, key: Optional[str] = None) -> bool:
""" Execute criteria """
Expand Down Expand Up @@ -64,7 +66,7 @@ def schedule_background_refresh(self):
def _submit(self) -> ResultDetail:
""" Submit criteria for execution (local or remote) """
# verify if query from snapshot
if (self._context.options.local):
if (self._context.options.local and not self._force_remote):
return self._execute_local_criteria()

try:
Expand Down
9 changes: 9 additions & 0 deletions switcher_client/switcher_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ def __init__(self, context: Context,key: Optional[str] = None):
self._throttle_period = 0
self._next_refresh_time = 0 # timestamp
self._default_result = None
self._force_remote = False

def check(self, strategy_type: str, input: str)-> Self:
""" Adds a strategy for validation """
Expand Down Expand Up @@ -55,6 +56,14 @@ def throttle(self, period: int) -> Self:

return self

def remote(self, force_remote: bool = True) -> Self:
""" Force the use of the remote API when local is enabled """
if not self._context.options.local:
raise ValueError("Local mode is not enabled")

self._force_remote = force_remote
return self

def default_result(self, result: bool) -> Self:
""" Sets the default result for the switcher """
self._default_result = result
Expand Down
35 changes: 33 additions & 2 deletions tests/test_switcher_remote.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from switcher_client.errors import RemoteAuthError
from switcher_client import Client
from switcher_client.lib.globals.global_auth import GlobalAuth
from switcher_client.lib.globals.global_context import ContextOptions

async_error = None

Expand Down Expand Up @@ -104,6 +105,35 @@ def test_remote_renew_token(httpx_mock):
switcher.is_on('MY_SWITCHER')
assert GlobalAuth.get_token() == '[new_token]'

def test_remote_with_remote_required_request(httpx_mock):
""" Should call the remote API with success for required remote request"""

# given
key = 'FF2FOR2022'
given_auth(httpx_mock)
given_check_criteria(httpx_mock, key=key, response={'result': True})
given_context(options=ContextOptions(local=True, snapshot_location='tests/snapshots'))
Client.load_snapshot()

switcher = Client.get_switcher()

# test
assert switcher.remote().is_on(key)

def test_remote_err_with_remote_reqquired_request_no_local():
""" Should raise an exception when local mode is not enabled and remote is forced """

# given
given_context(options=ContextOptions(local=False))

switcher = Client.get_switcher()

# test
with pytest.raises(ValueError) as excinfo:
switcher.remote().is_on('MY_SWITCHER')

assert 'Local mode is not enabled' in str(excinfo.value)

def test_remote_err_no_key(httpx_mock):
""" Should raise an exception when no key is provided """

Expand Down Expand Up @@ -186,12 +216,13 @@ def test_remote_err_check_criteria_default_result(httpx_mock):

# Helpers

def given_context(url='https://api.switcherapi.com', api_key='[API_KEY]'):
def given_context(url='https://api.switcherapi.com', api_key='[API_KEY]', options = ContextOptions()):
Client.build_context(
url=url,
api_key=api_key,
domain='Playground',
component='switcher-playground'
component='switcher-playground',
options=options
)

def given_auth(httpx_mock: HTTPXMock, status=200, token: Optional[str]='[token]', exp=int(round(time.time() * 1000))):
Expand Down