From 1b6adb6b4c4765b94a06262eab494c2571b024b3 Mon Sep 17 00:00:00 2001 From: stylianosgakis Date: Thu, 1 Feb 2024 14:13:21 +0100 Subject: [PATCH] Add the ability to remove toggle listeners that you have added (#69) * Fix synchronizing on the right object when adding a new listener * Add the ability to remove the toggle listeners --- .../kotlin/io/getunleash/UnleashClient.kt | 18 ++++++++++ .../kotlin/io/getunleash/UnleashClientSpec.kt | 2 ++ .../io/getunleash/polling/RefreshPolicy.kt | 14 +++++++- .../getunleash/polling/RefreshPolicyTest.kt | 34 +++++++++++++++++++ 4 files changed, 67 insertions(+), 1 deletion(-) diff --git a/src/main/kotlin/io/getunleash/UnleashClient.kt b/src/main/kotlin/io/getunleash/UnleashClient.kt index 5233be2..38def2e 100644 --- a/src/main/kotlin/io/getunleash/UnleashClient.kt +++ b/src/main/kotlin/io/getunleash/UnleashClient.kt @@ -155,6 +155,15 @@ class UnleashClient( refreshPolicy.addTogglesUpdatedListener(listener) } + /** + * Removes a TogglesUpdatedListener from our [io.getunleash.polling.RefreshPolicy] + * @param listener the listener to remove + * @since 0.2 + */ + override fun removeTogglesUpdatedListener(listener: TogglesUpdatedListener) { + refreshPolicy.removeTogglesUpdatedListener(listener) + } + /** * Adds a TogglesErroredListener to our [io.getunleash.polling.RefreshPolicy] * @param listener the listener to add @@ -163,4 +172,13 @@ class UnleashClient( override fun addTogglesErroredListener(listener: TogglesErroredListener) { refreshPolicy.addTogglesErroredListener(listener) } + + /** + * Removes a TogglesErroredListener from our [io.getunleash.polling.RefreshPolicy] + * @param listener The listener to remove + * @since 0.2 + */ + override fun removeTogglesErroredListener(listener: TogglesErroredListener) { + refreshPolicy.removeTogglesErroredListener(listener) + } } diff --git a/src/main/kotlin/io/getunleash/UnleashClientSpec.kt b/src/main/kotlin/io/getunleash/UnleashClientSpec.kt index ae62aab..8c0bb65 100644 --- a/src/main/kotlin/io/getunleash/UnleashClientSpec.kt +++ b/src/main/kotlin/io/getunleash/UnleashClientSpec.kt @@ -12,7 +12,9 @@ interface UnleashClientSpec : Closeable { fun updateContext(context: UnleashContext): CompletableFuture fun getContext(): UnleashContext fun addTogglesUpdatedListener(listener: TogglesUpdatedListener) + fun removeTogglesUpdatedListener(listener: TogglesUpdatedListener) fun addTogglesErroredListener(listener: TogglesErroredListener) + fun removeTogglesErroredListener(listener: TogglesErroredListener) fun startPolling() fun isPolling(): Boolean diff --git a/src/main/kotlin/io/getunleash/polling/RefreshPolicy.kt b/src/main/kotlin/io/getunleash/polling/RefreshPolicy.kt index 74e9d42..3479daf 100644 --- a/src/main/kotlin/io/getunleash/polling/RefreshPolicy.kt +++ b/src/main/kotlin/io/getunleash/polling/RefreshPolicy.kt @@ -135,17 +135,29 @@ abstract class RefreshPolicy( } fun addTogglesUpdatedListener(listener: TogglesUpdatedListener): Unit { - synchronized(listener) { + synchronized(listeners) { listeners.add(listener) } } + fun removeTogglesUpdatedListener(listener: TogglesUpdatedListener) { + synchronized(listeners) { + listeners.remove(listener) + } + } + fun addTogglesErroredListener(errorListener: TogglesErroredListener): Unit { synchronized(errorListeners) { errorListeners.add(errorListener) } } + fun removeTogglesErroredListener(listener: TogglesErroredListener): Unit { + synchronized(errorListeners) { + errorListeners.remove(listener) + } + } + fun addTogglesCheckedListener(checkListener: TogglesCheckedListener) { synchronized(checkListeners) { checkListeners.add(checkListener) diff --git a/src/test/kotlin/io/getunleash/polling/RefreshPolicyTest.kt b/src/test/kotlin/io/getunleash/polling/RefreshPolicyTest.kt index 98dadd6..f9b9bf9 100644 --- a/src/test/kotlin/io/getunleash/polling/RefreshPolicyTest.kt +++ b/src/test/kotlin/io/getunleash/polling/RefreshPolicyTest.kt @@ -1,7 +1,14 @@ package io.getunleash.polling +import io.getunleash.UnleashConfig +import io.getunleash.UnleashContext +import io.getunleash.data.Toggle +import java9.util.concurrent.CompletableFuture import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test +import org.mockito.kotlin.mock +import java.util.concurrent.atomic.AtomicBoolean +import java.util.concurrent.atomic.LongAdder class RefreshPolicyTest { @@ -11,4 +18,31 @@ class RefreshPolicyTest { val s = RefreshPolicy.sha256("expected") assertThat(s).isEqualTo("cea23dd4b87e8b00d19fb9ccaaef93e97353c7353e2070f3baf05aeb3995dff4") } + + @Test + fun `Can add and remove an update listener`() { + val refreshPolicy = object : RefreshPolicy( + unleashFetcher = mock(), + cache = mock(), + logger = mock(), + config = UnleashConfig("", ""), + context = UnleashContext(), + ) { + override val isReady: AtomicBoolean = AtomicBoolean(true) + + override fun getConfigurationAsync(): CompletableFuture> { + error("Not applicable") + } + + override fun startPolling() {} + override fun isPolling(): Boolean = false + } + val checks = LongAdder() + val togglesUpdatedListener = TogglesUpdatedListener { checks.add(1) } + refreshPolicy.addTogglesUpdatedListener(togglesUpdatedListener) + refreshPolicy.broadcastTogglesUpdated() + refreshPolicy.removeTogglesUpdatedListener(togglesUpdatedListener) + refreshPolicy.broadcastTogglesUpdated() + assertThat(checks.sum()).isEqualTo(1) + } } \ No newline at end of file