Skip to content

Commit

Permalink
Migrate files to kotlin (#10)
Browse files Browse the repository at this point in the history
  • Loading branch information
uniumuniu authored Oct 11, 2023
1 parent c5ba000 commit 2f2497b
Show file tree
Hide file tree
Showing 11 changed files with 397 additions and 118 deletions.
12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,13 +49,13 @@ We are breaking down the various parts that we need to migrate to Swift in the s
|---------------------|--------------------------------------------------|--------|
| Files | `@featurevisor/types` ➡️ `Types.kt` ||
| | SDK's `bucket.ts` ➡️ `Bucket.kt` ||
| | SDK's `conditions.ts` ➡️ `Conditions.kt` | 🟠 |
| | SDK's `datafileReader.ts` ➡️ `DatafileReader.kt` | |
| | SDK's `emitter.ts` ➡️ `Emitter.kt` | |
| | SDK's `feature.ts` ➡️ `Emitter.kt` | |
| | SDK's `instance.ts` ➡️ `Instance.kt` | |
| | SDK's `conditions.ts` ➡️ `Conditions.kt` | |
| | SDK's `datafileReader.ts` ➡️ `DatafileReader.kt` | |
| | SDK's `emitter.ts` ➡️ `Emitter.kt` | |
| | SDK's `feature.ts` ➡️ `Feature.kt` | |
| | SDK's `instance.ts` ➡️ `Instance.kt` | 🟠 |
| | SDK's `logger.ts` ➡️ `Logger.kt` | |
| | SDK's `segments.ts` ➡️ `segments.kt` | |
| | SDK's `segments.ts` ➡️ `Segments.kt` | |
| | | |
| Constructor options | `bucketKeySeparator` | |
| | `configureBucketKey` | |
Expand Down
2 changes: 1 addition & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ dependencies {
// Use the JUnit 5 integration.
testImplementation("org.junit.jupiter:junit-jupiter-engine:5.9.2")
// Uncomment when needed
// testImplementation("io.mockk:mockk:1.13.8")
testImplementation("io.mockk:mockk:1.13.8")
testImplementation("io.kotest:kotest-assertions-core:5.7.2")

testRuntimeOnly("org.junit.platform:junit-platform-launcher")
Expand Down
34 changes: 34 additions & 0 deletions src/main/kotlin/com/featurevisor/sdk/DataFileReader.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package com.featurevisor.sdk

import com.featurevisor.types.Attribute
import com.featurevisor.types.AttributeKey
import com.featurevisor.types.DatafileContent
import com.featurevisor.types.Feature
import com.featurevisor.types.FeatureKey
import com.featurevisor.types.Segment
import com.featurevisor.types.SegmentKey

class DataFileReader constructor(
datafileJson: DatafileContent,
) {
private val schemaVersion: String = datafileJson.schemaVersion
private val revision: String = datafileJson.revision
private val attributes: List<Attribute> = datafileJson.attributes
private val segments: List<Segment> = datafileJson.segments
private val features: List<Feature> = datafileJson.features

fun getRevision(): String = revision

fun getSchemaVersion(): String = schemaVersion

fun getAllAttributes(): List<Attribute> = attributes

fun getAttribute(attributeKey: AttributeKey): Attribute? =
attributes.find { attribute -> attribute.key == attributeKey }

fun getSegment(segmentKey: SegmentKey): Segment? =
segments.find { segment -> segment.key == segmentKey }

fun getFeature(featureKey: FeatureKey): Feature? =
features.find { feature -> feature.key == featureKey }
}
23 changes: 23 additions & 0 deletions src/main/kotlin/com/featurevisor/sdk/Emitter.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package com.featurevisor.sdk

import com.featurevisor.types.EventName

class Emitter {
private val listeners = mutableMapOf<EventName, () -> Unit>()

fun addListener(event: EventName, listener: () -> Unit) {
listeners.putIfAbsent(event, listener)
}

fun removeListener(event: EventName) {
listeners.remove(event)
}

fun removeAllListeners() {
listeners.clear()
}

fun emit(event: EventName) {
listeners.getOrDefault(event, null)?.invoke()
}
}
81 changes: 81 additions & 0 deletions src/main/kotlin/com/featurevisor/types/DataFile.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package com.featurevisor.types

/**
* Datafile-only types
*/
// 0 to 100,000
typealias Percentage = Int

data class Range(
val start: Percentage,
val end: Percentage,
)

data class Allocation(
val variation: VariationValue,
val range: Range,
)

data class Traffic(
val key: RuleKey,
val segments: GroupSegment,
val percentage: Percentage,

val enabled: Boolean?,
val variation: VariationValue?,
val variables: VariableValues?,

val allocation: List<Allocation>,
)

typealias PlainBucketBy = String

typealias AndBucketBy = List<BucketBy>

data class OrBucketBy(
val or: List<String>,
)

sealed class BucketBy {
data class Single(val bucketBy: PlainBucketBy) : BucketBy()
data class And(val bucketBy: AndBucketBy) : BucketBy()
data class Or(val bucketBy: OrBucketBy) : BucketBy()
}

data class RequiredWithVariation(
val key: FeatureKey,
val variation: VariationValue,
)

sealed class Required {
data class FeatureKey(val required: FeatureKey) : Required()
data class WithVariation(val required: RequiredWithVariation) : Required()
}

data class Feature(
val key: FeatureKey,
val deprecated: Boolean?,
val variablesSchema: List<VariableSchema>?,
val variations: List<Variation>?,
val bucketBy: BucketBy,
val required: List<Required>?,
val traffic: List<Traffic>,
val force: List<Force>?,

// if in a Group (mutex), these are available slot ranges
val ranges: List<Range>?,
)

data class DatafileContent(
val schemaVersion: String,
val revision: String,
val attributes: List<Attribute>,
val segments: List<Segment>,
val features: List<Feature>,
)

data class OverrideFeature(
val enabled: Boolean,
val variation: VariationValue?,
val variables: VariableValues?,
)
8 changes: 8 additions & 0 deletions src/main/kotlin/com/featurevisor/types/EventName.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.featurevisor.types

enum class EventName {
READY,
REFRESH,
UPDATE,
ACTIVATION,
}
32 changes: 32 additions & 0 deletions src/main/kotlin/com/featurevisor/types/Segment.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package com.featurevisor.types

typealias SegmentKey = String

data class Segment(
val archived: Boolean?,
val key: SegmentKey,
val conditions: Condition,
)

typealias PlainGroupSegment = SegmentKey

data class AndGroupSegment(
val and: List<GroupSegment>,
)

data class OrGroupSegment(
val or: List<GroupSegment>,
)

data class NotGroupSegment(
val not: List<GroupSegment>,
)

sealed class GroupSegment {
data class Plain(val segment: PlainGroupSegment) : GroupSegment()
data class Multiple(val segments: List<GroupSegment>) : GroupSegment()

data class And(val segment: AndGroupSegment) : GroupSegment()
data class Or(val segment: OrGroupSegment) : GroupSegment()
data class Not(val segment: NotGroupSegment) : GroupSegment()
}
111 changes: 0 additions & 111 deletions src/main/kotlin/com/featurevisor/types/Types.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,37 +2,6 @@ package com.featurevisor.types

typealias Context = Map<AttributeKey, AttributeValue>

typealias SegmentKey = String

data class Segment(
val archived: Boolean?,
val key: SegmentKey,
val conditions: Condition,
)

typealias PlainGroupSegment = SegmentKey

data class AndGroupSegment(
val and: List<GroupSegment>,
)

data class OrGroupSegment(
val or: List<GroupSegment>,
)

data class NotGroupSegment(
val not: List<GroupSegment>,
)

sealed class GroupSegment {
data class Plain(val segment: PlainGroupSegment) : GroupSegment()
data class Multiple(val segments: List<GroupSegment>) : GroupSegment()

data class And(val segment: AndGroupSegment) : GroupSegment()
data class Or(val segment: OrGroupSegment) : GroupSegment()
data class Not(val segment: NotGroupSegment) : GroupSegment()
}

typealias VariationValue = String

typealias VariableKey = String
Expand Down Expand Up @@ -124,86 +93,6 @@ typealias BucketKey = String
// 0 to 100,000
typealias BucketValue = Int

/**
* Datafile-only types
*/
// 0 to 100,000
typealias Percentage = Int

data class Range(
val start: Percentage,
val end: Percentage,
)

data class Allocation(
val variation: VariationValue,
val range: Range,
)

data class Traffic(
val key: RuleKey,
val segments: GroupSegment,
val percentage: Percentage,

val enabled: Boolean?,
val variation: VariationValue?,
val variables: VariableValues?,

val allocation: List<Allocation>,
)

typealias PlainBucketBy = String

typealias AndBucketBy = List<BucketBy>

data class OrBucketBy(
val or: List<String>,
)

sealed class BucketBy {
data class Single(val bucketBy: PlainBucketBy) : BucketBy()
data class And(val bucketBy: AndBucketBy) : BucketBy()
data class Or(val bucketBy: OrBucketBy) : BucketBy()
}

data class RequiredWithVariation(
val key: FeatureKey,
val variation: VariationValue,
)

sealed class Required {
data class FeatureKey(val required: FeatureKey) : Required()
data class WithVariation(val required: RequiredWithVariation) : Required()
}

data class Feature(
val key: FeatureKey,
val deprecated: Boolean?,
val variablesSchema: List<VariableSchema>?,
val variations: List<Variation>?,
val bucketBy: BucketBy,
val required: List<Required>?,
val traffic: List<Traffic>,
val force: List<Force>?,

// if in a Group (mutex), these are available slot ranges
val ranges: List<Range>?,
)

data class DatafileContent(
val schemaVersion: String,
val revision: String,
val attributes: List<Attribute>,
val segments: List<Segment>,
val features: List<Feature>,
)

data class OverrideFeature(
val enabled: Boolean,
val variation: VariationValue?,
val variables: VariableValues?,
)

typealias StickyFeatures = Map<FeatureKey, OverrideFeature>

typealias InitialFeatures = Map<FeatureKey, VariationValue>
Expand Down
49 changes: 49 additions & 0 deletions src/test/kotlin/com/featurevisor/sdk/DataFileReaderTest.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package com.featurevisor.sdk

import com.featurevisor.sdk.factory.DatafileContentFactory
import io.kotest.matchers.shouldBe
import org.junit.jupiter.api.Test

class DataFileReaderTest {

private val systemUnderTest = DataFileReader(
datafileJson = DatafileContentFactory.get()
)

@Test
fun `getRevision() returns correct value`() {
systemUnderTest.getRevision() shouldBe "revision"
}

@Test
fun `getSchemaVersion returns correct value`() {
systemUnderTest.getSchemaVersion() shouldBe "schemaVersion"
}

@Test
fun `getAllAttributes() returns correct list`() {
systemUnderTest.getAllAttributes() shouldBe DatafileContentFactory.getAttributes()
}

@Test
fun `getAttribute() returns correct value`() {
systemUnderTest.getAttribute("browser_type") shouldBe DatafileContentFactory.getAttributes().first()
}

@Test
fun `getSegment() returns correct value`() {
systemUnderTest.getSegment("netherlands") shouldBe DatafileContentFactory.getSegments().first()
}

@Test
fun `getFeature() returns correct value`() {
systemUnderTest.getFeature("landing_page") shouldBe DatafileContentFactory.getFeatures().first()
}

@Test
fun `return null if key not present in collection`() {
systemUnderTest.getAttribute("country") shouldBe null
systemUnderTest.getSegment("germany") shouldBe null
systemUnderTest.getFeature("key_moments") shouldBe null
}
}
Loading

0 comments on commit 2f2497b

Please sign in to comment.