Skip to content

Commit

Permalink
feat: run handlers immediately if provider already in associated state
Browse files Browse the repository at this point in the history
Signed-off-by: Federico Bond <federicobond@gmail.com>
  • Loading branch information
federicobond committed Mar 7, 2024
1 parent 44b6d06 commit 17b3369
Show file tree
Hide file tree
Showing 4 changed files with 62 additions and 13 deletions.
13 changes: 13 additions & 0 deletions openfeature/event.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,8 @@ def add_client_handler(
handlers = self._client_handlers[client][event]
handlers.append(handler)

self._run_immediate_handler(client, event, handler)

def remove_client_handler(
self, client: OpenFeatureClient, event: ProviderEvent, handler: EventHandler
) -> None:
Expand All @@ -84,6 +86,10 @@ def remove_client_handler(
def add_global_handler(self, event: ProviderEvent, handler: EventHandler) -> None:
self._global_handlers[event].append(handler)

from openfeature.api import get_client

self._run_immediate_handler(get_client(), event, handler)

def remove_global_handler(
self, event: ProviderEvent, handler: EventHandler
) -> None:
Expand All @@ -104,3 +110,10 @@ def run_handlers_for_provider(
for client in self._client_handlers:
if client.provider == provider:
self.run_client_handlers(client, event, details)

def _run_immediate_handler(
self, client: OpenFeatureClient, event: ProviderEvent, handler: EventHandler
) -> None:
if event == ProviderEvent.PROVIDER_READY:
# providers are assumed ready because provider status is not yet implemented
handler(EventDetails(provider_name=client.provider.get_metadata().name))
1 change: 0 additions & 1 deletion openfeature/exception.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ class ErrorCode(Enum):
TYPE_MISMATCH = "TYPE_MISMATCH"
TARGETING_KEY_MISSING = "TARGETING_KEY_MISSING"
INVALID_CONTEXT = "INVALID_CONTEXT"
PROVIDER_FATAL = "PROVIDER_FATAL"
GENERAL = "GENERAL"


Expand Down
45 changes: 39 additions & 6 deletions tests/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -249,12 +249,12 @@ def test_provider_events():
provider.get_metadata().name, provider_details
)

provider.emit_provider_ready(provider_details)
provider.emit_provider_configuration_changed(provider_details)
provider.emit_provider_error(provider_details)
provider.emit_provider_stale(provider_details)

spy.provider_ready.assert_called_once_with(details)
# NOTE: provider_ready is called immediately after adding the handler
spy.provider_ready.assert_called_once()
spy.provider_configuration_changed.assert_called_once_with(details)
spy.provider_error.assert_called_once_with(details)
spy.provider_stale.assert_called_once_with(details)
Expand All @@ -266,10 +266,43 @@ def test_add_remove_event_handler():

spy = MagicMock()

add_handler(ProviderEvent.PROVIDER_READY, spy.provider_ready)
remove_handler(ProviderEvent.PROVIDER_READY, spy.provider_ready)
add_handler(
ProviderEvent.PROVIDER_CONFIGURATION_CHANGED, spy.provider_configuration_changed
)
remove_handler(
ProviderEvent.PROVIDER_CONFIGURATION_CHANGED, spy.provider_configuration_changed
)

provider_details = ProviderEventDetails(message="message")
provider.emit_provider_ready(provider_details)
provider.emit_provider_configuration_changed(provider_details)

spy.provider_configuration_changed.assert_not_called()


# Requirement 5.3.3
def test_handlers_attached_to_provider_already_in_associated_state_should_run_immediately():
# Given
provider = NoOpProvider()
set_provider(provider)
spy = MagicMock()

# When
add_handler(ProviderEvent.PROVIDER_READY, spy.provider_ready)

# Then
spy.provider_ready.assert_called_once()

spy.provider_ready.assert_not_called()

def test_provider_ready_handlers_run_if_provider_initialize_function_terminates_normally():
# Given
provider = NoOpProvider()
set_provider(provider)

spy = MagicMock()
add_handler(ProviderEvent.PROVIDER_READY, spy.provider_ready)

# When
provider.initialize(get_evaluation_context())

# Then
spy.provider_ready.assert_called_once()
16 changes: 10 additions & 6 deletions tests/test_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,6 @@ def test_provider_events():
)

def emit_all_events(provider):
provider.emit_provider_ready(provider_details)
provider.emit_provider_configuration_changed(provider_details)
provider.emit_provider_error(provider_details)
provider.emit_provider_stale(provider_details)
Expand All @@ -270,7 +269,8 @@ def emit_all_events(provider):
emit_all_events(provider)
emit_all_events(other_provider)

spy.provider_ready.assert_called_once_with(details)
# NOTE: provider_ready is called immediately after adding the handler
spy.provider_ready.assert_called_once()
spy.provider_configuration_changed.assert_called_once_with(details)
spy.provider_error.assert_called_once_with(details)
spy.provider_stale.assert_called_once_with(details)
Expand All @@ -283,10 +283,14 @@ def test_add_remove_event_handler():
spy = MagicMock()

client = get_client()
client.add_handler(ProviderEvent.PROVIDER_READY, spy.provider_ready)
client.remove_handler(ProviderEvent.PROVIDER_READY, spy.provider_ready)
client.add_handler(
ProviderEvent.PROVIDER_CONFIGURATION_CHANGED, spy.provider_configuration_changed
)
client.remove_handler(
ProviderEvent.PROVIDER_CONFIGURATION_CHANGED, spy.provider_configuration_changed
)

provider_details = ProviderEventDetails(message="message")
provider.emit_provider_ready(provider_details)
provider.emit_provider_configuration_changed(provider_details)

spy.provider_ready.assert_not_called()
spy.provider_configuration_changed.assert_not_called()

0 comments on commit 17b3369

Please sign in to comment.