Skip to content

Commit

Permalink
update TestClient to allow @MockBean usage (#6311)
Browse files Browse the repository at this point in the history
  • Loading branch information
colesnodgrass committed May 5, 2023
1 parent c8be076 commit 969e197
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 14 deletions.
21 changes: 18 additions & 3 deletions airbyte-featureflag/src/main/kotlin/Client.kt
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ import com.launchdarkly.sdk.LDContext
import com.launchdarkly.sdk.server.LDClient
import io.micronaut.context.annotation.Property
import io.micronaut.context.annotation.Requires
import io.micronaut.context.annotation.Secondary
import jakarta.inject.Inject
import jakarta.inject.Singleton
import org.slf4j.LoggerFactory
import java.lang.Thread.MIN_PRIORITY
Expand Down Expand Up @@ -149,15 +151,28 @@ class LaunchDarklyClient(private val client: LDClient) : FeatureFlagClient {
}

/**
* Test feature-flag client.
* Test feature-flag client. Only to be used in test scenarios.
*
* Intended only for usage in testing scenarios. Can also be mocked in unit tests.
* This class can be mocked and can also be used with Micronaut's @MockBean annotation to replace the [FeatureFlagClient] dependency.
*
* To use with the @MockBean annotation define the following method within your @MicronautTest annotated test class:
* ```java
* @MockBean(FeatureFlagClient.class)
* TestClient featureFlagClient() {
* return mock(TestClient.class);
* }
* ```
*
* All [Flag] instances will use the provided [values] map as their source of truth, including [EnvVar] flags.
*
* @param [values] is a map of [Flag.key] to its status.
*/
class TestClient @JvmOverloads constructor(val values: Map<String, Any> = mapOf()) : FeatureFlagClient {
@Secondary
open class TestClient(val values: Map<String, Any>) : FeatureFlagClient {

@Inject
constructor() : this(mapOf())

override fun boolVariation(flag: Flag<Boolean>, context: Context): Boolean {
return when (flag) {
is EnvVar -> {
Expand Down
40 changes: 34 additions & 6 deletions airbyte-featureflag/src/test/kotlin/ClientTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import com.launchdarkly.sdk.server.LDClient
import io.micronaut.context.annotation.Bean
import io.micronaut.context.annotation.Property
import io.micronaut.context.annotation.Replaces
import io.micronaut.test.annotation.MockBean
import io.micronaut.test.extensions.junit5.annotation.MicronautTest
import io.mockk.called
import io.mockk.clearMocks
Expand All @@ -16,6 +17,7 @@ import io.mockk.mockk
import io.mockk.slot
import io.mockk.verify
import jakarta.inject.Inject
import jakarta.inject.Singleton
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
import java.nio.file.Path
Expand All @@ -26,7 +28,6 @@ import kotlin.io.path.writeText
import kotlin.test.Ignore
import kotlin.test.assertEquals
import kotlin.test.assertFalse
import kotlin.test.assertNotNull
import kotlin.test.assertTrue

/** workspaceId used across multiple tests */
Expand Down Expand Up @@ -404,27 +405,24 @@ class InjectTest {
}

@Inject
var featureFlagClient: FeatureFlagClient? = null
lateinit var featureFlagClient: FeatureFlagClient

@Test
fun `ConfigFileClient loads if no client property defined`() {
assertNotNull(featureFlagClient)
assertTrue { featureFlagClient is ConfigFileClient }
assertTrue { featureFlagClient?.boolVariation(flag, context) ?: false }
}

@Property(name = CONFIG_FF_CLIENT, value = "")
@Test
fun `ConfigFileClient loads if client property is empty`() {
assertNotNull(featureFlagClient)
assertTrue { featureFlagClient is ConfigFileClient }
assertTrue { featureFlagClient?.boolVariation(flag, context) ?: false }
}

@Property(name = CONFIG_FF_CLIENT, value = "not-launchdarkly")
@Test
fun `ConfigFileClient loads if client property is not ${CONFIG_FF_CLIENT_VAL_LAUNCHDARKLY}`() {
assertNotNull(featureFlagClient)
assertTrue { featureFlagClient is ConfigFileClient }
assertTrue { featureFlagClient?.boolVariation(flag, context) ?: false }
}
Expand All @@ -434,8 +432,38 @@ class InjectTest {
fun `LaunchDarklyClient loads if client is defined as ${CONFIG_FF_CLIENT_VAL_LAUNCHDARKLY}`() {
every { ldClient.boolVariation(flag.key, any<LDContext>(), flag.default) } returns flag.default

assertNotNull(featureFlagClient)
assertTrue { featureFlagClient is LaunchDarklyClient }
assertTrue { featureFlagClient?.boolVariation(flag, context) ?: false }
}
}

@MicronautTest(rebuildContext = true)
class NonMockBeanTest {
@Singleton
class Dummy(val ffClient: FeatureFlagClient)

@Inject
lateinit var dummy: Dummy

@Test
fun `ensure ConfigFileClient is injected when no MockBean is defined`() {
assertTrue { dummy.ffClient is ConfigFileClient }
}
}

@MicronautTest(rebuildContext = true)
class MockBeanTest {
@Singleton
class Dummy(val ffClient: FeatureFlagClient)

@Inject
lateinit var dummy: Dummy

@Test
fun `ensure MockBean is injected when @MockBean is defined`() {
assertTrue { dummy.ffClient is TestClient }
}

@MockBean(FeatureFlagClient::class)
fun featureFlagClient(): TestClient = mockk<TestClient>()
}
13 changes: 8 additions & 5 deletions spotbugs-exclude-filter-file.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,21 @@

<!-- examples: https://spotbugs.readthedocs.io/en/stable/filter.html#complete-example -->
<Match>
<Source name="~.*build/generated.*" />
<Source name="~.*build/generated.*"/>
</Match>
<Match>
<Package name="io.airbyte.workers.general.jmh_generated.*" />
<Package name="io.airbyte.workers.general.jmh_generated.*"/>
</Match>
<Match>
<Package name="io.airbyte.api.client.*" />
<Package name="io.airbyte.api.client.*"/>
</Match>
<!-- Suppress warning about use if InputStream#readObject. The usage is safe because it is not from an untrusted source. -->
<Match>
<Class name="io.airbyte.integrations.debezium.internals.AirbyteFileOffsetBackingStore" />
<Bug code="SECOBDES" />
<Class name="io.airbyte.integrations.debezium.internals.AirbyteFileOffsetBackingStore"/>
<Bug code="SECOBDES"/>
</Match>
<Match>
<Source name="~.*\.kt"/>
</Match>
<Match>
<Package name="io.airbyte.server.repositories.domain.*" />
Expand Down

0 comments on commit 969e197

Please sign in to comment.