From e530f2f22227ac44c16eff4338efce4472e6fa01 Mon Sep 17 00:00:00 2001 From: hsinha610 Date: Wed, 17 Apr 2024 03:38:16 +0530 Subject: [PATCH] Added: Explicit API - Strict mode in Kotlin Helps in preventing internal API being published as public API. --- build.gradle.kts | 5 + .../kotlin/com/featurevisor/sdk/Bucket.kt | 2 +- .../kotlin/com/featurevisor/sdk/Conditions.kt | 2 +- .../com/featurevisor/sdk/DatafileReader.kt | 2 +- .../kotlin/com/featurevisor/sdk/Emitter.kt | 2 +- .../com/featurevisor/sdk/FeaturevisorError.kt | 12 +- .../featurevisor/sdk/Instance+Activation.kt | 2 +- .../featurevisor/sdk/Instance+Evaluation.kt | 14 +- .../com/featurevisor/sdk/Instance+Feature.kt | 6 +- .../com/featurevisor/sdk/Instance+Fetch.kt | 2 +- .../com/featurevisor/sdk/Instance+Refresh.kt | 4 +- .../com/featurevisor/sdk/Instance+Status.kt | 2 +- .../com/featurevisor/sdk/Instance+Variable.kt | 16 +- .../kotlin/com/featurevisor/sdk/Instance.kt | 28 +-- .../com/featurevisor/sdk/InstanceOptions.kt | 6 +- .../kotlin/com/featurevisor/sdk/Logger.kt | 22 +- .../sdk/serializers/Serializers.kt | 14 +- .../testRunner/BenchmarkFeature.kt | 12 +- .../testRunner/CommandExecuter.kt | 2 +- .../com/featurevisor/testRunner/Matrix.kt | 16 +- .../featurevisor/testRunner/TestExecuter.kt | 4 +- .../featurevisor/testRunner/TestFeature.kt | 2 +- .../featurevisor/testRunner/TestSegment.kt | 2 +- .../com/featurevisor/testRunner/Utils.kt | 24 +-- .../kotlin/com/featurevisor/types/Types.kt | 190 +++++++++--------- 25 files changed, 199 insertions(+), 194 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 20280f7..8d8b9d0 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -7,6 +7,7 @@ import org.gradle.api.tasks.testing.logging.TestExceptionFormat import org.gradle.api.tasks.testing.logging.TestLogEvent +import org.jetbrains.kotlin.gradle.dsl.ExplicitApiMode.Strict plugins { // Apply the org.jetbrains.kotlin.jvm Plugin to add support for Kotlin. @@ -44,6 +45,10 @@ publishing { } } +kotlin { + explicitApi = Strict +} + dependencies { // Use the Kotlin JUnit 5 integration. testImplementation("org.jetbrains.kotlin:kotlin-test-junit5") diff --git a/src/main/kotlin/com/featurevisor/sdk/Bucket.kt b/src/main/kotlin/com/featurevisor/sdk/Bucket.kt index 49ebabf..d34743a 100644 --- a/src/main/kotlin/com/featurevisor/sdk/Bucket.kt +++ b/src/main/kotlin/com/featurevisor/sdk/Bucket.kt @@ -3,7 +3,7 @@ package com.featurevisor.sdk import com.goncalossilva.murmurhash.MurmurHash3 import kotlin.math.floor -object Bucket { +internal object Bucket { private const val HASH_SEED = 1u private const val MAX_HASH_VALUE = 4294967296 // 2^32 diff --git a/src/main/kotlin/com/featurevisor/sdk/Conditions.kt b/src/main/kotlin/com/featurevisor/sdk/Conditions.kt index 2bda4ec..c9d41e1 100644 --- a/src/main/kotlin/com/featurevisor/sdk/Conditions.kt +++ b/src/main/kotlin/com/featurevisor/sdk/Conditions.kt @@ -30,7 +30,7 @@ import com.featurevisor.types.Operator.SEMVER_NOT_EQUALS import com.featurevisor.types.Operator.STARTS_WITH import net.swiftzer.semver.SemVer -object Conditions { +internal object Conditions { fun conditionIsMatched(condition: Plain, context: Context): Boolean { val (attributeKey, operator, conditionValue) = condition diff --git a/src/main/kotlin/com/featurevisor/sdk/DatafileReader.kt b/src/main/kotlin/com/featurevisor/sdk/DatafileReader.kt index eef4c77..707cab7 100644 --- a/src/main/kotlin/com/featurevisor/sdk/DatafileReader.kt +++ b/src/main/kotlin/com/featurevisor/sdk/DatafileReader.kt @@ -8,7 +8,7 @@ import com.featurevisor.types.FeatureKey import com.featurevisor.types.Segment import com.featurevisor.types.SegmentKey -class DatafileReader constructor( +internal class DatafileReader constructor( datafileJson: DatafileContent, ) { diff --git a/src/main/kotlin/com/featurevisor/sdk/Emitter.kt b/src/main/kotlin/com/featurevisor/sdk/Emitter.kt index b5cafdf..19764b3 100644 --- a/src/main/kotlin/com/featurevisor/sdk/Emitter.kt +++ b/src/main/kotlin/com/featurevisor/sdk/Emitter.kt @@ -2,7 +2,7 @@ package com.featurevisor.sdk import com.featurevisor.types.EventName -class Emitter { +internal class Emitter { private val listeners = mutableMapOf) -> Unit>() diff --git a/src/main/kotlin/com/featurevisor/sdk/FeaturevisorError.kt b/src/main/kotlin/com/featurevisor/sdk/FeaturevisorError.kt index 064c5ff..5a22f9b 100644 --- a/src/main/kotlin/com/featurevisor/sdk/FeaturevisorError.kt +++ b/src/main/kotlin/com/featurevisor/sdk/FeaturevisorError.kt @@ -1,22 +1,22 @@ package com.featurevisor.sdk -sealed class FeaturevisorError(message: String) : Throwable(message = message) { +public sealed class FeaturevisorError(message: String) : Throwable(message = message) { /// Thrown when attempting to init Featurevisor instance without passing datafile and datafileUrl. /// At least one of them is required to init the SDK correctly - object MissingDatafileOptions : FeaturevisorError("Missing data file options") + public object MissingDatafileOptions : FeaturevisorError("Missing data file options") - class FetchingDataFileFailed(val result: String) : FeaturevisorError("Fetching data file failed") + public class FetchingDataFileFailed(public val result: String) : FeaturevisorError("Fetching data file failed") /// Thrown when receiving unparseable Datafile JSON responses. /// - Parameters: /// - data: The data being parsed. /// - errorMessage: The message from the error which occured during parsing. - class UnparsableJson(val data: String?, errorMessage: String) : FeaturevisorError(errorMessage) + public class UnparsableJson(public val data: String?, errorMessage: String) : FeaturevisorError(errorMessage) /// Thrown when attempting to construct an invalid URL. /// - Parameter string: The invalid URL string. - class InvalidUrl(val url: String?) : FeaturevisorError("Invalid URL") + public class InvalidUrl(public val url: String?) : FeaturevisorError("Invalid URL") - object MissingDatafileUrlWhileRefreshing : FeaturevisorError("Missing datafile url need to refresh") + public object MissingDatafileUrlWhileRefreshing : FeaturevisorError("Missing datafile url need to refresh") } diff --git a/src/main/kotlin/com/featurevisor/sdk/Instance+Activation.kt b/src/main/kotlin/com/featurevisor/sdk/Instance+Activation.kt index 3454b0b..dfd0bf0 100644 --- a/src/main/kotlin/com/featurevisor/sdk/Instance+Activation.kt +++ b/src/main/kotlin/com/featurevisor/sdk/Instance+Activation.kt @@ -6,7 +6,7 @@ import com.featurevisor.types.EventName.ACTIVATION import com.featurevisor.types.FeatureKey import com.featurevisor.types.VariationValue -fun FeaturevisorInstance.activate(featureKey: FeatureKey, context: Context = emptyMap()): VariationValue? { +public fun FeaturevisorInstance.activate(featureKey: FeatureKey, context: Context = emptyMap()): VariationValue? { val evaluation = evaluateVariation(featureKey, context) val variationValue = evaluation.variation?.value ?: evaluation.variationValue ?: return null val finalContext = interceptContext?.invoke(context) ?: context diff --git a/src/main/kotlin/com/featurevisor/sdk/Instance+Evaluation.kt b/src/main/kotlin/com/featurevisor/sdk/Instance+Evaluation.kt index dc65951..69ee054 100644 --- a/src/main/kotlin/com/featurevisor/sdk/Instance+Evaluation.kt +++ b/src/main/kotlin/com/featurevisor/sdk/Instance+Evaluation.kt @@ -24,7 +24,7 @@ import kotlinx.serialization.json.Json import kotlinx.serialization.json.decodeFromJsonElement import kotlinx.serialization.json.encodeToJsonElement -enum class EvaluationReason(val value: String) { +public enum class EvaluationReason(public val value: String) { NOT_FOUND("not_found"), NO_VARIATIONS("no_variations"), DISABLED("disabled"), @@ -41,7 +41,7 @@ enum class EvaluationReason(val value: String) { } @Serializable -data class Evaluation( +public data class Evaluation( val featureKey: FeatureKey, val reason: EvaluationReason, val bucketValue: BucketValue? = null, @@ -56,7 +56,7 @@ data class Evaluation( val variableValue: VariableValue? = null, val variableSchema: VariableSchema? = null, ) { - fun toDictionary(): Map { + public fun toDictionary(): Map { val data = try { val json = Json.encodeToJsonElement(this) Json.decodeFromJsonElement>(json) @@ -68,13 +68,13 @@ data class Evaluation( } } -fun FeaturevisorInstance.isEnabled(featureKey: FeatureKey, context: Context = emptyMap()): Boolean { +public fun FeaturevisorInstance.isEnabled(featureKey: FeatureKey, context: Context = emptyMap()): Boolean { val evaluation = evaluateFlag(featureKey, context) return evaluation.enabled == true } @Suppress("UNREACHABLE_CODE") -fun FeaturevisorInstance.evaluateVariation(featureKey: FeatureKey, context: Context = emptyMap()): Evaluation { +public fun FeaturevisorInstance.evaluateVariation(featureKey: FeatureKey, context: Context = emptyMap()): Evaluation { var evaluation: Evaluation try { val flag = evaluateFlag(featureKey, context) @@ -231,7 +231,7 @@ fun FeaturevisorInstance.evaluateVariation(featureKey: FeatureKey, context: Cont @Suppress("UNREACHABLE_CODE") -fun FeaturevisorInstance.evaluateFlag(featureKey: FeatureKey, context: Context = emptyMap()): Evaluation { +public fun FeaturevisorInstance.evaluateFlag(featureKey: FeatureKey, context: Context = emptyMap()): Evaluation { var evaluation: Evaluation @@ -443,7 +443,7 @@ fun FeaturevisorInstance.evaluateFlag(featureKey: FeatureKey, context: Context = } @Suppress("UNREACHABLE_CODE") -fun FeaturevisorInstance.evaluateVariable( +public fun FeaturevisorInstance.evaluateVariable( featureKey: FeatureKey, variableKey: VariableKey, context: Context = emptyMap(), diff --git a/src/main/kotlin/com/featurevisor/sdk/Instance+Feature.kt b/src/main/kotlin/com/featurevisor/sdk/Instance+Feature.kt index 46cd705..5af30a4 100644 --- a/src/main/kotlin/com/featurevisor/sdk/Instance+Feature.kt +++ b/src/main/kotlin/com/featurevisor/sdk/Instance+Feature.kt @@ -7,11 +7,11 @@ import com.featurevisor.types.Feature import com.featurevisor.types.Force import com.featurevisor.types.Traffic -fun FeaturevisorInstance.getFeatureByKey(featureKey: String): Feature? { +public fun FeaturevisorInstance.getFeatureByKey(featureKey: String): Feature? { return datafileReader.getFeature(featureKey) } -fun FeaturevisorInstance.getFeature(featureKey: String): Feature?{ +public fun FeaturevisorInstance.getFeature(featureKey: String): Feature?{ return datafileReader.getFeature(featureKey) } @@ -58,7 +58,7 @@ internal fun FeaturevisorInstance.getMatchedAllocation( } } -data class MatchedTrafficAndAllocation( +internal data class MatchedTrafficAndAllocation( val matchedTraffic: Traffic?, val matchedAllocation: Allocation?, ) diff --git a/src/main/kotlin/com/featurevisor/sdk/Instance+Fetch.kt b/src/main/kotlin/com/featurevisor/sdk/Instance+Fetch.kt index ea950c8..56c5317 100644 --- a/src/main/kotlin/com/featurevisor/sdk/Instance+Fetch.kt +++ b/src/main/kotlin/com/featurevisor/sdk/Instance+Fetch.kt @@ -40,7 +40,7 @@ private fun fetchDatafileContentFromUrl( } } -const val BODY_BYTE_COUNT = 1000000L +internal const val BODY_BYTE_COUNT = 1000000L private inline fun fetch( request: Request, crossinline completion: (Result) -> Unit, diff --git a/src/main/kotlin/com/featurevisor/sdk/Instance+Refresh.kt b/src/main/kotlin/com/featurevisor/sdk/Instance+Refresh.kt index f3094e6..bc3918d 100644 --- a/src/main/kotlin/com/featurevisor/sdk/Instance+Refresh.kt +++ b/src/main/kotlin/com/featurevisor/sdk/Instance+Refresh.kt @@ -8,7 +8,7 @@ import kotlinx.coroutines.delay import kotlinx.coroutines.isActive import kotlinx.coroutines.launch -fun FeaturevisorInstance.startRefreshing() = when { +public fun FeaturevisorInstance.startRefreshing(): Unit? = when { datafileUrl == null -> { logger?.error("cannot start refreshing since `datafileUrl` is not provided") throw MissingDatafileUrlWhileRefreshing @@ -26,7 +26,7 @@ fun FeaturevisorInstance.startRefreshing() = when { } } -fun FeaturevisorInstance.stopRefreshing() { +public fun FeaturevisorInstance.stopRefreshing() { refreshJob?.cancel() refreshJob = null logger?.warn("refreshing has stopped") diff --git a/src/main/kotlin/com/featurevisor/sdk/Instance+Status.kt b/src/main/kotlin/com/featurevisor/sdk/Instance+Status.kt index 9cb74d6..9a0709a 100644 --- a/src/main/kotlin/com/featurevisor/sdk/Instance+Status.kt +++ b/src/main/kotlin/com/featurevisor/sdk/Instance+Status.kt @@ -1,6 +1,6 @@ package com.featurevisor.sdk -data class Statuses(var ready: Boolean, var refreshInProgress: Boolean) +internal data class Statuses(var ready: Boolean, var refreshInProgress: Boolean) internal fun FeaturevisorInstance.isReady(): Boolean { return statuses.ready diff --git a/src/main/kotlin/com/featurevisor/sdk/Instance+Variable.kt b/src/main/kotlin/com/featurevisor/sdk/Instance+Variable.kt index 925f20d..b08af22 100644 --- a/src/main/kotlin/com/featurevisor/sdk/Instance+Variable.kt +++ b/src/main/kotlin/com/featurevisor/sdk/Instance+Variable.kt @@ -16,7 +16,7 @@ import kotlinx.serialization.json.Json import kotlinx.serialization.json.decodeFromJsonElement import kotlinx.serialization.json.encodeToJsonElement -fun FeaturevisorInstance.getVariable( +public fun FeaturevisorInstance.getVariable( featureKey: FeatureKey, variableKey: VariableKey, context: Context = emptyMap(), @@ -30,7 +30,7 @@ fun FeaturevisorInstance.getVariable( return evaluation.variableValue } -fun FeaturevisorInstance.getVariableBoolean( +public fun FeaturevisorInstance.getVariableBoolean( featureKey: FeatureKey, variableKey: VariableKey, context: Context, @@ -38,7 +38,7 @@ fun FeaturevisorInstance.getVariableBoolean( return (getVariable(featureKey, variableKey, context) as? BooleanValue)?.value } -fun FeaturevisorInstance.getVariableString( +public fun FeaturevisorInstance.getVariableString( featureKey: FeatureKey, variableKey: VariableKey, context: Context, @@ -46,7 +46,7 @@ fun FeaturevisorInstance.getVariableString( return (getVariable(featureKey, variableKey, context) as? StringValue)?.value } -fun FeaturevisorInstance.getVariableInteger( +public fun FeaturevisorInstance.getVariableInteger( featureKey: FeatureKey, variableKey: VariableKey, context: Context, @@ -54,7 +54,7 @@ fun FeaturevisorInstance.getVariableInteger( return (getVariable(featureKey, variableKey, context) as? IntValue)?.value } -fun FeaturevisorInstance.getVariableDouble( +public fun FeaturevisorInstance.getVariableDouble( featureKey: FeatureKey, variableKey: VariableKey, context: Context, @@ -62,7 +62,7 @@ fun FeaturevisorInstance.getVariableDouble( return (getVariable(featureKey, variableKey, context) as? DoubleValue)?.value } -fun FeaturevisorInstance.getVariableArray( +public fun FeaturevisorInstance.getVariableArray( featureKey: FeatureKey, variableKey: VariableKey, context: Context, @@ -70,7 +70,7 @@ fun FeaturevisorInstance.getVariableArray( return (getVariable(featureKey, variableKey, context) as? ArrayValue)?.values } -inline fun FeaturevisorInstance.getVariableObject( +public inline fun FeaturevisorInstance.getVariableObject( featureKey: FeatureKey, variableKey: VariableKey, context: Context, @@ -84,7 +84,7 @@ inline fun FeaturevisorInstance.getVariableObject( } } -inline fun FeaturevisorInstance.getVariableJSON( +public inline fun FeaturevisorInstance.getVariableJSON( featureKey: FeatureKey, variableKey: VariableKey, context: Context, diff --git a/src/main/kotlin/com/featurevisor/sdk/Instance.kt b/src/main/kotlin/com/featurevisor/sdk/Instance.kt index d833849..ee0a285 100644 --- a/src/main/kotlin/com/featurevisor/sdk/Instance.kt +++ b/src/main/kotlin/com/featurevisor/sdk/Instance.kt @@ -10,12 +10,12 @@ import kotlinx.coroutines.Job import kotlinx.serialization.decodeFromString import kotlinx.serialization.json.Json -typealias ConfigureBucketKey = (Feature, Context, BucketKey) -> BucketKey -typealias ConfigureBucketValue = (Feature, Context, BucketValue) -> BucketValue -typealias InterceptContext = (Context) -> Context -typealias DatafileFetchHandler = (datafileUrl: String) -> Result +internal typealias ConfigureBucketKey = (Feature, Context, BucketKey) -> BucketKey +internal typealias ConfigureBucketValue = (Feature, Context, BucketValue) -> BucketValue +internal typealias InterceptContext = (Context) -> Context +internal typealias DatafileFetchHandler = (datafileUrl: String) -> Result -var emptyDatafile = DatafileContent( +internal var emptyDatafile = DatafileContent( schemaVersion = "1", revision = "unknown", attributes = emptyList(), @@ -23,14 +23,14 @@ var emptyDatafile = DatafileContent( features = emptyList(), ) -class FeaturevisorInstance private constructor(options: InstanceOptions) { +public class FeaturevisorInstance private constructor(options: InstanceOptions) { - companion object { - fun createInstance(options: InstanceOptions): FeaturevisorInstance { + public companion object { + public fun createInstance(options: InstanceOptions): FeaturevisorInstance { return FeaturevisorInstance(options) } - var companionLogger: Logger? = null + public var companionLogger: Logger? = null } private val on: (EventName, Listener) -> Unit @@ -118,11 +118,11 @@ class FeaturevisorInstance private constructor(options: InstanceOptions) { } } - fun setLogLevels(levels: List) { + public fun setLogLevels(levels: List) { this.logger?.setLevels(levels) } - fun setDatafile(datafileJSON: String) { + public fun setDatafile(datafileJSON: String) { val data = datafileJSON.toByteArray(Charsets.UTF_8) try { val datafileContent = Json.decodeFromString(String(data)) @@ -132,15 +132,15 @@ class FeaturevisorInstance private constructor(options: InstanceOptions) { } } - fun setDatafile(datafileContent: DatafileContent) { + public fun setDatafile(datafileContent: DatafileContent) { datafileReader = DatafileReader(datafileJson = datafileContent) } - fun setStickyFeatures(stickyFeatures: StickyFeatures?) { + public fun setStickyFeatures(stickyFeatures: StickyFeatures?) { this.stickyFeatures = stickyFeatures } - fun getRevision(): String { + public fun getRevision(): String { return datafileReader.getRevision() } } diff --git a/src/main/kotlin/com/featurevisor/sdk/InstanceOptions.kt b/src/main/kotlin/com/featurevisor/sdk/InstanceOptions.kt index 48254db..6acf9e6 100644 --- a/src/main/kotlin/com/featurevisor/sdk/InstanceOptions.kt +++ b/src/main/kotlin/com/featurevisor/sdk/InstanceOptions.kt @@ -4,9 +4,9 @@ import com.featurevisor.types.DatafileContent import com.featurevisor.types.InitialFeatures import com.featurevisor.types.StickyFeatures -typealias Listener = (Array) -> Unit +public typealias Listener = (Array) -> Unit -data class InstanceOptions( +public data class InstanceOptions( val bucketKeySeparator: String = defaultBucketKeySeparator, val configureBucketKey: ConfigureBucketKey? = null, val configureBucketValue: ConfigureBucketValue? = null, @@ -24,7 +24,7 @@ data class InstanceOptions( val refreshInterval: Long? = null, // seconds val stickyFeatures: StickyFeatures? = null, ) { - companion object { + internal companion object { private const val defaultBucketKeySeparator = "." } } diff --git a/src/main/kotlin/com/featurevisor/sdk/Logger.kt b/src/main/kotlin/com/featurevisor/sdk/Logger.kt index df3c183..0a9afa3 100644 --- a/src/main/kotlin/com/featurevisor/sdk/Logger.kt +++ b/src/main/kotlin/com/featurevisor/sdk/Logger.kt @@ -5,20 +5,20 @@ import com.featurevisor.sdk.Logger.LogLevel.ERROR import com.featurevisor.sdk.Logger.LogLevel.INFO import com.featurevisor.sdk.Logger.LogLevel.WARN -typealias LogDetails = Map -typealias LogHandler = (level: Logger.LogLevel, message: String, details: LogDetails?) -> Unit +public typealias LogDetails = Map +public typealias LogHandler = (level: Logger.LogLevel, message: String, details: LogDetails?) -> Unit -class Logger( +public class Logger( private var levels: List, private val handle: LogHandler, ) { - companion object { + public companion object { private val defaultLogLevels: List = listOf(ERROR, WARN) private val defaultLogHandler: LogHandler = { level, message, _ -> println("[${level.value}] $message") } - fun createLogger( + public fun createLogger( levels: List = defaultLogLevels, handle: LogHandler = defaultLogHandler, ): Logger { @@ -26,23 +26,23 @@ class Logger( } } - fun setLevels(levels: List) { + public fun setLevels(levels: List) { this.levels = levels } - fun debug(message: String, details: LogDetails? = null) { + public fun debug(message: String, details: LogDetails? = null) { log(DEBUG, message, details) } - fun info(message: String, details: LogDetails? = null) { + public fun info(message: String, details: LogDetails? = null) { log(INFO, message, details) } - fun warn(message: String, details: LogDetails? = null) { + public fun warn(message: String, details: LogDetails? = null) { log(WARN, message, details) } - fun error(message: String, details: LogDetails? = null) { + public fun error(message: String, details: LogDetails? = null) { log(ERROR, message, details) } @@ -52,7 +52,7 @@ class Logger( } } - enum class LogLevel(val value: String) { + public enum class LogLevel(public val value: String) { ERROR("error"), WARN("warn"), INFO("info"), diff --git a/src/main/kotlin/com/featurevisor/sdk/serializers/Serializers.kt b/src/main/kotlin/com/featurevisor/sdk/serializers/Serializers.kt index 43456dc..abb26c3 100644 --- a/src/main/kotlin/com/featurevisor/sdk/serializers/Serializers.kt +++ b/src/main/kotlin/com/featurevisor/sdk/serializers/Serializers.kt @@ -25,7 +25,7 @@ import java.text.SimpleDateFormat @OptIn(InternalSerializationApi::class, ExperimentalSerializationApi::class) @Serializer(forClass = Required::class) -object RequiredSerializer: KSerializer{ +internal object RequiredSerializer: KSerializer{ override val descriptor: SerialDescriptor = buildSerialDescriptor("package.Required", PolymorphicKind.SEALED) @@ -50,7 +50,7 @@ object RequiredSerializer: KSerializer{ @OptIn(InternalSerializationApi::class) @Serializer(forClass = Condition::class) -object ConditionSerializer : KSerializer { +public object ConditionSerializer : KSerializer { override val descriptor: SerialDescriptor = buildSerialDescriptor("package.Condition", PolymorphicKind.SEALED) @@ -125,7 +125,7 @@ object ConditionSerializer : KSerializer { @OptIn(InternalSerializationApi::class) @Serializer(forClass = GroupSegment::class) -object GroupSegmentSerializer : KSerializer { +public object GroupSegmentSerializer : KSerializer { override val descriptor: SerialDescriptor = buildSerialDescriptor("package.GroupSegment", PolymorphicKind.SEALED) @@ -201,7 +201,7 @@ object GroupSegmentSerializer : KSerializer { @OptIn(InternalSerializationApi::class) @Serializer(forClass = BucketBy::class) -object BucketBySerializer : KSerializer { +public object BucketBySerializer : KSerializer { override val descriptor: SerialDescriptor = buildSerialDescriptor("package.BucketBy", PolymorphicKind.SEALED) @@ -245,7 +245,7 @@ object BucketBySerializer : KSerializer { @OptIn(InternalSerializationApi::class) @Serializer(forClass = ConditionValue::class) -object ConditionValueSerializer : KSerializer { +public object ConditionValueSerializer : KSerializer { override val descriptor: SerialDescriptor = buildSerialDescriptor("package.ConditionValue", PolymorphicKind.SEALED) @@ -288,7 +288,7 @@ object ConditionValueSerializer : KSerializer { @OptIn(InternalSerializationApi::class) @Serializer(forClass = VariableValue::class) -object VariableValueSerializer : KSerializer { +public object VariableValueSerializer : KSerializer { override val descriptor: SerialDescriptor = buildSerialDescriptor("package.VariableValue", PolymorphicKind.SEALED) @@ -332,7 +332,7 @@ object VariableValueSerializer : KSerializer { } } -fun isValidJson(jsonString: String): Boolean { +public fun isValidJson(jsonString: String): Boolean { return try { // Attempt to parse the string Json.decodeFromString>(jsonString) diff --git a/src/main/kotlin/com/featurevisor/testRunner/BenchmarkFeature.kt b/src/main/kotlin/com/featurevisor/testRunner/BenchmarkFeature.kt index f3a05c8..df87119 100644 --- a/src/main/kotlin/com/featurevisor/testRunner/BenchmarkFeature.kt +++ b/src/main/kotlin/com/featurevisor/testRunner/BenchmarkFeature.kt @@ -6,12 +6,12 @@ import com.featurevisor.sdk.getVariation import com.featurevisor.sdk.isEnabled import com.featurevisor.types.* -data class BenchmarkOutput( +internal data class BenchmarkOutput( val value: Any? = null, val duration: Double ) -data class BenchMarkOptions( +internal data class BenchMarkOptions( val environment: String = "", val feature: String = "", val n: Int = 0, @@ -21,7 +21,7 @@ data class BenchMarkOptions( val variable: String? = null, ) -fun benchmarkFeature(option: BenchMarkOptions) { +internal fun benchmarkFeature(option: BenchMarkOptions) { println("Running benchmark for feature ${option.feature}...") println("Building datafile containing all features for ${option.environment}...") @@ -83,7 +83,7 @@ fun benchmarkFeature(option: BenchMarkOptions) { } -fun benchmarkFeatureFlag( +internal fun benchmarkFeatureFlag( f: FeaturevisorInstance, feature: FeatureKey, context: Context, @@ -105,7 +105,7 @@ fun benchmarkFeatureFlag( } -fun benchmarkFeatureVariation( +internal fun benchmarkFeatureVariation( f: FeaturevisorInstance, feature: FeatureKey, context: Context, @@ -126,7 +126,7 @@ fun benchmarkFeatureVariation( ) } -fun benchmarkFeatureVariable( +internal fun benchmarkFeatureVariable( f: FeaturevisorInstance, feature: FeatureKey, variableKey: VariableKey, diff --git a/src/main/kotlin/com/featurevisor/testRunner/CommandExecuter.kt b/src/main/kotlin/com/featurevisor/testRunner/CommandExecuter.kt index 910a73f..4a9dd89 100644 --- a/src/main/kotlin/com/featurevisor/testRunner/CommandExecuter.kt +++ b/src/main/kotlin/com/featurevisor/testRunner/CommandExecuter.kt @@ -12,7 +12,7 @@ internal fun getJsonForFeatureUsingCommand(featureName: String, environment: Str null } -fun getJsonForDataFile(environment: String, projectRootPath: String) = +internal fun getJsonForDataFile(environment: String, projectRootPath: String) = try { createCommandAccordingToEnvironment(environment).runCommand(getFileForSpecificPath(projectRootPath)) } catch (e: Exception) { diff --git a/src/main/kotlin/com/featurevisor/testRunner/Matrix.kt b/src/main/kotlin/com/featurevisor/testRunner/Matrix.kt index 136145b..155cd38 100644 --- a/src/main/kotlin/com/featurevisor/testRunner/Matrix.kt +++ b/src/main/kotlin/com/featurevisor/testRunner/Matrix.kt @@ -2,7 +2,7 @@ package com.featurevisor.testRunner import com.featurevisor.types.* -fun generateCombinations( +internal fun generateCombinations( keys: List, matrix: AssertionMatrix, idx: Int, @@ -23,7 +23,7 @@ fun generateCombinations( } } -fun getMatrixCombinations(matrix: AssertionMatrix): List> { +internal fun getMatrixCombinations(matrix: AssertionMatrix): List> { val keys = matrix.keys.toList() if (keys.isEmpty()) { @@ -35,7 +35,7 @@ fun getMatrixCombinations(matrix: AssertionMatrix): List): Any? { +internal fun applyCombinationToValue(value: Any?, combination: Map): Any? { if (value is String) { val variableKeysInValue = Regex("""\$\{\{\s*([^\s}]+)\s*}}""").findAll(value) @@ -52,7 +52,7 @@ fun applyCombinationToValue(value: Any?, combination: Map, assertion: FeatureAssertion ): FeatureAssertion { @@ -86,7 +86,7 @@ fun applyCombinationToFeatureAssertion( return flattenedAssertion } -fun getFeatureAssertionsFromMatrix( +internal fun getFeatureAssertionsFromMatrix( aIndex: Int, assertionWithMatrix: FeatureAssertion ): List { @@ -111,7 +111,7 @@ fun getFeatureAssertionsFromMatrix( } @Suppress("IMPLICIT_CAST_TO_ANY") -fun getAtValue(at: WeightType) = when (at) { +internal fun getAtValue(at: WeightType) = when (at) { is WeightType.IntType -> { at.value } @@ -125,7 +125,7 @@ fun getAtValue(at: WeightType) = when (at) { } } -fun applyCombinationToSegmentAssertion( +internal fun applyCombinationToSegmentAssertion( combination: Map, assertion: SegmentAssertion ): SegmentAssertion { @@ -143,7 +143,7 @@ fun applyCombinationToSegmentAssertion( return flattenedAssertion } -fun getSegmentAssertionsFromMatrix( +internal fun getSegmentAssertionsFromMatrix( aIndex: Int, assertionWithMatrix: SegmentAssertion ): List { diff --git a/src/main/kotlin/com/featurevisor/testRunner/TestExecuter.kt b/src/main/kotlin/com/featurevisor/testRunner/TestExecuter.kt index b2e9f69..017659f 100644 --- a/src/main/kotlin/com/featurevisor/testRunner/TestExecuter.kt +++ b/src/main/kotlin/com/featurevisor/testRunner/TestExecuter.kt @@ -3,7 +3,7 @@ package com.featurevisor.testRunner import com.featurevisor.types.* import java.io.File -data class TestProjectOption( +internal data class TestProjectOption( val keyPattern: String = "", val assertionPattern: String = "", val verbose: Boolean = false, @@ -14,7 +14,7 @@ data class TestProjectOption( val projectRootPath: String = getRootProjectDir() ) -fun startTest(option: TestProjectOption) { +internal fun startTest(option: TestProjectOption) { var hasError = false val folder = File("${option.projectRootPath}/${option.testDirPath}") val listOfFiles = folder.listFiles()?.sortedBy { it } diff --git a/src/main/kotlin/com/featurevisor/testRunner/TestFeature.kt b/src/main/kotlin/com/featurevisor/testRunner/TestFeature.kt index d8fb584..580933c 100644 --- a/src/main/kotlin/com/featurevisor/testRunner/TestFeature.kt +++ b/src/main/kotlin/com/featurevisor/testRunner/TestFeature.kt @@ -9,7 +9,7 @@ import kotlinx.serialization.decodeFromString import kotlinx.serialization.json.Json import kotlinx.serialization.json.JsonElement -fun testFeature(testFeature: TestFeature, dataFile: DataFile, option: TestProjectOption): TestResult { +internal fun testFeature(testFeature: TestFeature, dataFile: DataFile, option: TestProjectOption): TestResult { val testStartTime = System.currentTimeMillis() val featureKey = testFeature.key diff --git a/src/main/kotlin/com/featurevisor/testRunner/TestSegment.kt b/src/main/kotlin/com/featurevisor/testRunner/TestSegment.kt index a943a0d..08c3f49 100644 --- a/src/main/kotlin/com/featurevisor/testRunner/TestSegment.kt +++ b/src/main/kotlin/com/featurevisor/testRunner/TestSegment.kt @@ -6,7 +6,7 @@ import com.featurevisor.types.TestResultAssertion import com.featurevisor.types.TestResultAssertionError import com.featurevisor.types.TestSegment -fun testSegment(testSegment: TestSegment, option: TestProjectOption): TestResult { +internal fun testSegment(testSegment: TestSegment, option: TestProjectOption): TestResult { val testStartTime = System.currentTimeMillis() val segmentKey = testSegment.key diff --git a/src/main/kotlin/com/featurevisor/testRunner/Utils.kt b/src/main/kotlin/com/featurevisor/testRunner/Utils.kt index e140ca3..9ecf916 100644 --- a/src/main/kotlin/com/featurevisor/testRunner/Utils.kt +++ b/src/main/kotlin/com/featurevisor/testRunner/Utils.kt @@ -77,7 +77,7 @@ internal fun getRootProjectDir(): String { throw IllegalStateException("Root project directory not found.") } -fun prettyDuration(diffInMs: Long): String { +internal fun prettyDuration(diffInMs: Long): String { var diff = abs(diffInMs) if (diff == 0L) { @@ -155,7 +155,7 @@ internal fun printTestResult(testResult: TestResult) { } } -fun getContextValue(contextValue: Any?) = +internal fun getContextValue(contextValue: Any?) = when (contextValue) { is Boolean -> AttributeValue.BooleanValue(contextValue) is Int -> AttributeValue.IntValue(contextValue) @@ -166,7 +166,7 @@ fun getContextValue(contextValue: Any?) = else -> throw Exception("Unsupported context value") } -fun getContextValues(contextValue: AttributeValue?) = +internal fun getContextValues(contextValue: AttributeValue?) = when (contextValue) { is AttributeValue.IntValue -> contextValue.value is AttributeValue.DoubleValue -> contextValue.value @@ -176,7 +176,7 @@ fun getContextValues(contextValue: AttributeValue?) = null -> null } -fun checkIfArraysAreEqual(a: Array, b: Array): Boolean { +internal fun checkIfArraysAreEqual(a: Array, b: Array): Boolean { if (a.size != b.size) return false for (i in a.indices) { @@ -187,7 +187,7 @@ fun checkIfArraysAreEqual(a: Array, b: Array): Boolean { return true } -fun checkIfObjectsAreEqual(a: Any?, b: Any?): Boolean { +internal fun checkIfObjectsAreEqual(a: Any?, b: Any?): Boolean { if (a === b) { return true } @@ -215,7 +215,7 @@ fun checkIfObjectsAreEqual(a: Any?, b: Any?): Boolean { return true } -fun stringToArray(input: String): List? { +internal fun stringToArray(input: String): List? { if (input.trim().startsWith("[") && input.trim().endsWith("]")) { val trimmed = input.trim().substring(1, input.length - 1) val elements = trimmed.split(",").map { it.trim() } @@ -231,19 +231,19 @@ fun stringToArray(input: String): List? { return null } -fun checkJsonIsEquals(a: String, b: String): Boolean { +internal fun checkJsonIsEquals(a: String, b: String): Boolean { val map1 = Json.decodeFromString>(a) val map2 = Json.decodeFromString>(b) return map1 == map2 } -fun buildDataFileForBothEnvironments(projectRootPath: String): DataFile = +internal fun buildDataFileForBothEnvironments(projectRootPath: String): DataFile = DataFile( stagingDataFiles = buildDataFileForStaging(projectRootPath), productionDataFiles = buildDataFileForProduction(projectRootPath) ) -fun buildDataFileForStaging(projectRootPath: String) = try { +internal fun buildDataFileForStaging(projectRootPath: String) = try { getJsonForDataFile(environment = "staging", projectRootPath = projectRootPath)?.run { convertToDataClass() } @@ -252,7 +252,7 @@ fun buildDataFileForStaging(projectRootPath: String) = try { null } -fun buildDataFileForProduction(projectRootPath: String) = try { +internal fun buildDataFileForProduction(projectRootPath: String) = try { getJsonForDataFile(environment = "production", projectRootPath = projectRootPath)?.run { convertToDataClass() } @@ -262,7 +262,7 @@ fun buildDataFileForProduction(projectRootPath: String) = try { null } -fun getDataFileContent(featureName: String, environment: String, projectRootPath: String) = +internal fun getDataFileContent(featureName: String, environment: String, projectRootPath: String) = try { getJsonForFeatureUsingCommand( featureName = featureName, @@ -276,7 +276,7 @@ fun getDataFileContent(featureName: String, environment: String, projectRootPath null } -fun convertNanoSecondToMilliSecond(timeInNanoSecond:Double):String { +internal fun convertNanoSecondToMilliSecond(timeInNanoSecond:Double):String { val timeInMilliSecond = timeInNanoSecond/1000000 return if (timeInMilliSecond > 1000){ "${timeInMilliSecond / 1000} s" diff --git a/src/main/kotlin/com/featurevisor/types/Types.kt b/src/main/kotlin/com/featurevisor/types/Types.kt index 3357c32..d5336cd 100644 --- a/src/main/kotlin/com/featurevisor/types/Types.kt +++ b/src/main/kotlin/com/featurevisor/types/Types.kt @@ -5,12 +5,12 @@ import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable import java.util.* -typealias Context = Map -typealias VariationValue = String -typealias VariableKey = String +public typealias Context = Map +public typealias VariationValue = String +public typealias VariableKey = String @Serializable -enum class VariableType { +public enum class VariableType { @SerialName("boolean") BOOLEAN, @SerialName("string") @@ -27,21 +27,21 @@ enum class VariableType { JSON } -typealias VariableObjectValue = Map +public typealias VariableObjectValue = Map @Serializable(with = VariableValueSerializer::class) -sealed class VariableValue { - data class BooleanValue(val value: Boolean) : VariableValue() - data class StringValue(val value: String) : VariableValue() - data class IntValue(val value: Int) : VariableValue() - data class DoubleValue(val value: Double) : VariableValue() - data class ArrayValue(val values: List) : VariableValue() - data class ObjectValue(val value: VariableObjectValue) : VariableValue() - data class JsonValue(val value: String) : VariableValue() +public sealed class VariableValue { + public data class BooleanValue(val value: Boolean) : VariableValue() + public data class StringValue(val value: String) : VariableValue() + public data class IntValue(val value: Int) : VariableValue() + public data class DoubleValue(val value: Double) : VariableValue() + public data class ArrayValue(val values: List) : VariableValue() + public data class ObjectValue(val value: VariableObjectValue) : VariableValue() + public data class JsonValue(val value: String) : VariableValue() } @Serializable -data class VariableOverride( +public data class VariableOverride( val value: VariableValue, // one of the below must be present in YAML @@ -50,14 +50,14 @@ data class VariableOverride( ) @Serializable -data class Variable( +public data class Variable( val key: VariableKey, val value: VariableValue, val overrides: List? = null, ) @Serializable -data class Variation( +public data class Variation( // only available in YAML val description: String? = null, @@ -70,18 +70,18 @@ data class Variation( ) @Serializable -data class VariableSchema( +public data class VariableSchema( val key: VariableKey, val type: VariableType, val defaultValue: VariableValue, ) -typealias FeatureKey = String +public typealias FeatureKey = String -typealias VariableValues = Map +public typealias VariableValues = Map @Serializable -data class Force( +public data class Force( // one of the below must be present in YAML val conditions: Condition? = null, val segments: GroupSegment? = null, @@ -91,7 +91,7 @@ data class Force( val variables: VariableValues? = null, ) -data class Slot( +public data class Slot( // @TODO: allow false? val feature: FeatureKey? = null, @@ -99,27 +99,27 @@ data class Slot( val percentage: Weight, ) -data class Group( +public data class Group( val key: String, val description: String, val slots: List, ) -typealias BucketKey = String +public typealias BucketKey = String // 0 to 100,000 -typealias BucketValue = Int -typealias StickyFeatures = Map -typealias InitialFeatures = Map +public typealias BucketValue = Int +public typealias StickyFeatures = Map +public typealias InitialFeatures = Map /** * YAML-only type */ // 0 to 100 -typealias Weight = Double -typealias EnvironmentKey = String -typealias RuleKey = String +internal typealias Weight = Double +internal typealias EnvironmentKey = String +internal typealias RuleKey = String -data class Rule( +public data class Rule( val key: RuleKey, val segments: GroupSegment, val percentage: Weight, @@ -129,15 +129,15 @@ data class Rule( val variables: VariableValues? = null, ) -data class Environment( +public data class Environment( val expose: Boolean? = null, val rules: List, val force: List? = null, ) -typealias Environments = Map +public typealias Environments = Map -data class ParsedFeature( +public data class ParsedFeature( val key: FeatureKey, val archived: Boolean?, @@ -156,80 +156,80 @@ data class ParsedFeature( val environments: Environments, ) -typealias AttributeKey = String +public typealias AttributeKey = String @Serializable -data class Attribute( +public data class Attribute( val key: AttributeKey, val type: String, val archived: Boolean? = null, val capture: Boolean? = null, ) -sealed class AttributeValue { - data class StringValue(val value: String?) : AttributeValue() - data class IntValue(val value: Int) : AttributeValue() - data class DoubleValue(val value: Double) : AttributeValue() - data class BooleanValue(val value: Boolean) : AttributeValue() - data class DateValue(val value: Date) : AttributeValue() +public sealed class AttributeValue { + public data class StringValue(val value: String?) : AttributeValue() + public data class IntValue(val value: Int) : AttributeValue() + public data class DoubleValue(val value: Double) : AttributeValue() + public data class BooleanValue(val value: Boolean) : AttributeValue() + public data class DateValue(val value: Date) : AttributeValue() } @Serializable(with = ConditionSerializer::class) -sealed class Condition { - data class Plain( +public sealed class Condition { + public data class Plain( val attributeKey: AttributeKey, val operator: Operator, val value: ConditionValue, ) : Condition() - data class And(val and: List) : Condition() - data class Or(val or: List) : Condition() - data class Not(val not: List) : Condition() + public data class And(val and: List) : Condition() + public data class Or(val or: List) : Condition() + public data class Not(val not: List) : Condition() } -const val TAG = "FeaturevisorService" +public const val TAG: String = "FeaturevisorService" @Serializable(with = ConditionValueSerializer::class) -sealed class ConditionValue { - data class StringValue(val value: String?) : ConditionValue() - data class IntValue(val value: Int) : ConditionValue() - data class DoubleValue(val value: Double) : ConditionValue() - data class BooleanValue(val value: Boolean) : ConditionValue() - data class ArrayValue(val values: List) : ConditionValue() - data class DateTimeValue(val value: Date) : ConditionValue() +public sealed class ConditionValue { + public data class StringValue(val value: String?) : ConditionValue() + public data class IntValue(val value: Int) : ConditionValue() + public data class DoubleValue(val value: Double) : ConditionValue() + public data class BooleanValue(val value: Boolean) : ConditionValue() + public data class ArrayValue(val values: List) : ConditionValue() + public data class DateTimeValue(val value: Date) : ConditionValue() } -typealias SegmentKey = String +public typealias SegmentKey = String @Serializable -data class Segment( +public data class Segment( val archived: Boolean? = null, val key: SegmentKey, val conditions: Condition, ) -data class AndGroupSegment( +public data class AndGroupSegment( val and: List, ) -data class OrGroupSegment( +public data class OrGroupSegment( val or: List, ) -data class NotGroupSegment( +public data class NotGroupSegment( val not: List, ) @Serializable(with = GroupSegmentSerializer::class) -sealed class GroupSegment { - data class Plain(val segment: SegmentKey) : GroupSegment() - data class Multiple(val segments: List) : GroupSegment() - data class And(val segment: AndGroupSegment) : GroupSegment() - data class Or(val segment: OrGroupSegment) : GroupSegment() - data class Not(val segment: NotGroupSegment) : GroupSegment() +public sealed class GroupSegment { + public data class Plain(val segment: SegmentKey) : GroupSegment() + public data class Multiple(val segments: List) : GroupSegment() + public data class And(val segment: AndGroupSegment) : GroupSegment() + public data class Or(val segment: OrGroupSegment) : GroupSegment() + public data class Not(val segment: NotGroupSegment) : GroupSegment() } -enum class Operator(val value: String) { +public enum class Operator(public val value: String) { EQUALS("equals"), NOT_EQUALS("notEquals"), @@ -262,7 +262,7 @@ enum class Operator(val value: String) { NOT_IN_ARRAY("notIn"); } -enum class EventName { +public enum class EventName { READY, REFRESH, UPDATE, @@ -274,18 +274,18 @@ enum class EventName { * Datafile-only types */ // 0 to 100,000 -typealias Percentage = Int +internal typealias Percentage = Int -typealias Range = List +internal typealias Range = List @Serializable -data class Allocation( +public data class Allocation( val variation: VariationValue, val range: Range, ) @Serializable -data class Traffic( +public data class Traffic( val key: RuleKey, val segments: GroupSegment, val percentage: Percentage, @@ -298,25 +298,25 @@ data class Traffic( ) @Serializable(with = BucketBySerializer::class) -sealed class BucketBy { - data class Single(val bucketBy: String) : BucketBy() - data class And(val bucketBy: List) : BucketBy() - data class Or(val bucketBy: List) : BucketBy() +public sealed class BucketBy { + public data class Single(val bucketBy: String) : BucketBy() + public data class And(val bucketBy: List) : BucketBy() + public data class Or(val bucketBy: List) : BucketBy() } -data class RequiredWithVariation( +public data class RequiredWithVariation( val key: FeatureKey, val variation: VariationValue, ) @Serializable(with = RequiredSerializer::class) -sealed class Required { - data class FeatureKey(val required: com.featurevisor.types.FeatureKey) : Required() - data class WithVariation(val required: RequiredWithVariation) : Required() +public sealed class Required { + public data class FeatureKey(val required: com.featurevisor.types.FeatureKey) : Required() + public data class WithVariation(val required: RequiredWithVariation) : Required() } @Serializable -data class Feature( +public data class Feature( val key: FeatureKey, val deprecated: Boolean? = null, val variablesSchema: List? = null, @@ -331,7 +331,7 @@ data class Feature( ) @Serializable -data class DatafileContent( +public data class DatafileContent( val schemaVersion: String, val revision: String, val attributes: List, @@ -340,7 +340,7 @@ data class DatafileContent( ) @Serializable -data class OverrideFeature( +public data class OverrideFeature( val enabled: Boolean, val variation: VariationValue? = null, val variables: VariableValues? = null, @@ -350,10 +350,10 @@ data class OverrideFeature( * Tests */ -typealias AssertionMatrix = Map> +internal typealias AssertionMatrix = Map> -data class FeatureAssertion( +internal data class FeatureAssertion( var description: String?=null, var environment: EnvironmentKey="staging", // bucket weight: 0 to 100 @@ -365,29 +365,29 @@ data class FeatureAssertion( val matrix: AssertionMatrix? = null ) -data class TestFeature( +internal data class TestFeature( val key: FeatureKey, val assertions: List, ) -data class SegmentAssertion( +internal data class SegmentAssertion( var description: String?=null, var context: Context, val expectedToMatch: Boolean, val matrix: AssertionMatrix? = null ) -data class TestSegment( +internal data class TestSegment( val key: SegmentKey, val assertions: List, ) -sealed class Test { +internal sealed class Test { data class Feature(val value: TestFeature) : Test() data class Segment(val value: TestSegment) : Test() } -sealed class WeightType{ +internal sealed class WeightType{ data class IntType(val value: Int):WeightType() data class DoubleType(val value: Double):WeightType() @@ -395,7 +395,7 @@ sealed class WeightType{ data class StringType(val value: String):WeightType() } -data class TestResultAssertionError( +internal data class TestResultAssertionError( val type: String, val expected: Any?=null, val actual: Any?=null, @@ -403,7 +403,7 @@ data class TestResultAssertionError( val details: Map?=null ) -data class TestResultAssertion( +internal data class TestResultAssertion( val description: String, val environment: EnvironmentKey? = null, var duration: Long, @@ -411,7 +411,7 @@ data class TestResultAssertion( val errors: List? ) -data class TestResult( +internal data class TestResult( val type: String, val key: FeatureKey, var notFound: Boolean?=null, @@ -420,17 +420,17 @@ data class TestResult( val assertions: List ) -data class ExecutionResult( +internal data class ExecutionResult( var passed: Boolean, val assertionsCount: AssertionsCount ) -data class AssertionsCount( +internal data class AssertionsCount( var passed: Int=0, var failed: Int=0 ) -data class DataFile( +internal data class DataFile( val stagingDataFiles: DatafileContent? = null, val productionDataFiles: DatafileContent? = null )