feat(kotlin-sdk): add ByteLystPlatform unified entry point + 2 new test files (4.2)
New source: - ByteLystPlatform.kt — unified entry point wiring all services via Context + Config (secureStore, client, auth, telemetry, flags, killSwitch, auditLog) - start(userId?) / stop() lifecycle for telemetry + flags - Mirrors Swift ByteLystPlatform API New tests (2 files): - BLKillSwitchResultTest — ok(), disabled, default, copy - BLTelemetryEventTest — serialize, deserialize, optional fields
This commit is contained in:
parent
933390e89b
commit
70635ba80e
@ -0,0 +1,80 @@
|
|||||||
|
package com.bytelyst.platform
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unified entry point for the ByteLyst platform SDK.
|
||||||
|
*
|
||||||
|
* Creates and wires all platform services from a single config + context.
|
||||||
|
* Mirrors the Swift `ByteLystPlatform` API.
|
||||||
|
*
|
||||||
|
* Usage:
|
||||||
|
* ```kotlin
|
||||||
|
* val platform = ByteLystPlatform(
|
||||||
|
* context = applicationContext,
|
||||||
|
* config = BLPlatformConfig(
|
||||||
|
* productId = "chronomind",
|
||||||
|
* baseUrl = "https://api.chronomind.app",
|
||||||
|
* applicationId = "com.chronomind.app"
|
||||||
|
* )
|
||||||
|
* )
|
||||||
|
*
|
||||||
|
* platform.start()
|
||||||
|
* platform.telemetry.trackScreen("home")
|
||||||
|
* val isNew = platform.flags.isEnabled("new_feature")
|
||||||
|
* platform.stop()
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
class ByteLystPlatform(
|
||||||
|
context: Context,
|
||||||
|
val config: BLPlatformConfig,
|
||||||
|
) {
|
||||||
|
/** Secure storage (EncryptedSharedPreferences). */
|
||||||
|
val secureStore: BLSecureStore = BLSecureStore(context, config.applicationId)
|
||||||
|
|
||||||
|
/** HTTP client shared by services that need a token provider. */
|
||||||
|
val client: BLPlatformClient = BLPlatformClient(config) {
|
||||||
|
secureStore.getString("access_token")
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Auth client (login, register, refresh, MFA, etc.). */
|
||||||
|
val auth: BLAuthClient = BLAuthClient(config, secureStore)
|
||||||
|
|
||||||
|
/** Telemetry event tracking + batch flush. */
|
||||||
|
val telemetry: BLTelemetryClient = BLTelemetryClient(config, context)
|
||||||
|
|
||||||
|
/** Feature flag polling. */
|
||||||
|
val flags: BLFeatureFlagClient = BLFeatureFlagClient(config)
|
||||||
|
|
||||||
|
/** Kill switch checker. */
|
||||||
|
val killSwitch: BLKillSwitchClient = BLKillSwitchClient(config)
|
||||||
|
|
||||||
|
/** Local rotating audit log. */
|
||||||
|
val auditLog: BLAuditLogger = BLAuditLogger(context, config)
|
||||||
|
|
||||||
|
/** Whether [start] has been called. */
|
||||||
|
var isStarted: Boolean = false
|
||||||
|
private set
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start all services: telemetry flush timer, feature flag polling.
|
||||||
|
* Call on app launch / Activity.onCreate.
|
||||||
|
*/
|
||||||
|
fun start(userId: String? = null) {
|
||||||
|
if (isStarted) return
|
||||||
|
isStarted = true
|
||||||
|
telemetry.start()
|
||||||
|
flags.init(userId)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stop all services: flush telemetry, stop flag polling.
|
||||||
|
* Call on app background / Activity.onDestroy.
|
||||||
|
*/
|
||||||
|
fun stop() {
|
||||||
|
if (!isStarted) return
|
||||||
|
isStarted = false
|
||||||
|
telemetry.stop()
|
||||||
|
flags.stop()
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,39 @@
|
|||||||
|
package com.bytelyst.platform
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Assertions.*
|
||||||
|
import org.junit.jupiter.api.Test
|
||||||
|
|
||||||
|
class BLKillSwitchResultTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `ok() should return not-disabled result`() {
|
||||||
|
val result = BLKillSwitchClient.KillSwitchResult.ok()
|
||||||
|
assertFalse(result.disabled)
|
||||||
|
assertNull(result.message)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `disabled result should have message`() {
|
||||||
|
val result = BLKillSwitchClient.KillSwitchResult(
|
||||||
|
disabled = true,
|
||||||
|
message = "Under maintenance"
|
||||||
|
)
|
||||||
|
assertTrue(result.disabled)
|
||||||
|
assertEquals("Under maintenance", result.message)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `default result should not be disabled`() {
|
||||||
|
val result = BLKillSwitchClient.KillSwitchResult()
|
||||||
|
assertFalse(result.disabled)
|
||||||
|
assertNull(result.message)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `data class copy should work`() {
|
||||||
|
val original = BLKillSwitchClient.KillSwitchResult.ok()
|
||||||
|
val modified = original.copy(disabled = true, message = "Updating")
|
||||||
|
assertTrue(modified.disabled)
|
||||||
|
assertEquals("Updating", modified.message)
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,92 @@
|
|||||||
|
package com.bytelyst.platform
|
||||||
|
|
||||||
|
import kotlinx.serialization.encodeToString
|
||||||
|
import kotlinx.serialization.json.Json
|
||||||
|
import org.junit.jupiter.api.Assertions.*
|
||||||
|
import org.junit.jupiter.api.Test
|
||||||
|
|
||||||
|
class BLTelemetryEventTest {
|
||||||
|
|
||||||
|
private val json = Json { ignoreUnknownKeys = true; encodeDefaults = true }
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `event should serialize to JSON`() {
|
||||||
|
val event = BLTelemetryClient.TelemetryEvent(
|
||||||
|
id = "evt-1",
|
||||||
|
productId = "testapp",
|
||||||
|
anonymousInstallId = "inst-1",
|
||||||
|
sessionId = "sess-1",
|
||||||
|
platform = "android",
|
||||||
|
channel = "native",
|
||||||
|
osFamily = "android",
|
||||||
|
osVersion = "14",
|
||||||
|
appVersion = "1.0.0",
|
||||||
|
buildNumber = "42",
|
||||||
|
releaseChannel = "beta",
|
||||||
|
eventType = "info",
|
||||||
|
module = "test",
|
||||||
|
eventName = "unit_test",
|
||||||
|
occurredAt = "2026-01-01T00:00:00Z",
|
||||||
|
)
|
||||||
|
val jsonStr = json.encodeToString(event)
|
||||||
|
assertTrue(jsonStr.contains("\"productId\":\"testapp\""))
|
||||||
|
assertTrue(jsonStr.contains("\"eventName\":\"unit_test\""))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `event should deserialize from JSON`() {
|
||||||
|
val jsonStr = """
|
||||||
|
{
|
||||||
|
"id": "evt-1",
|
||||||
|
"productId": "testapp",
|
||||||
|
"anonymousInstallId": "inst-1",
|
||||||
|
"sessionId": "sess-1",
|
||||||
|
"platform": "android",
|
||||||
|
"channel": "native",
|
||||||
|
"osFamily": "android",
|
||||||
|
"osVersion": "14",
|
||||||
|
"appVersion": "1.0.0",
|
||||||
|
"buildNumber": "42",
|
||||||
|
"releaseChannel": "beta",
|
||||||
|
"eventType": "info",
|
||||||
|
"module": "test",
|
||||||
|
"eventName": "unit_test",
|
||||||
|
"occurredAt": "2026-01-01T00:00:00Z"
|
||||||
|
}
|
||||||
|
""".trimIndent()
|
||||||
|
val event = json.decodeFromString<BLTelemetryClient.TelemetryEvent>(jsonStr)
|
||||||
|
assertEquals("testapp", event.productId)
|
||||||
|
assertEquals("unit_test", event.eventName)
|
||||||
|
assertNull(event.feature)
|
||||||
|
assertNull(event.tags)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `event with optional fields should serialize correctly`() {
|
||||||
|
val event = BLTelemetryClient.TelemetryEvent(
|
||||||
|
id = "evt-2",
|
||||||
|
productId = "testapp",
|
||||||
|
anonymousInstallId = "inst-1",
|
||||||
|
sessionId = "sess-1",
|
||||||
|
platform = "android",
|
||||||
|
channel = "native",
|
||||||
|
osFamily = "android",
|
||||||
|
osVersion = "14",
|
||||||
|
appVersion = "1.0.0",
|
||||||
|
buildNumber = "42",
|
||||||
|
releaseChannel = "beta",
|
||||||
|
eventType = "error",
|
||||||
|
module = "auth",
|
||||||
|
eventName = "login_failed",
|
||||||
|
feature = "social_login",
|
||||||
|
message = "Token expired",
|
||||||
|
tags = mapOf("provider" to "google"),
|
||||||
|
metrics = mapOf("retryCount" to 3.0),
|
||||||
|
occurredAt = "2026-01-01T00:00:00Z",
|
||||||
|
)
|
||||||
|
val jsonStr = json.encodeToString(event)
|
||||||
|
assertTrue(jsonStr.contains("\"feature\":\"social_login\""))
|
||||||
|
assertTrue(jsonStr.contains("\"provider\":\"google\""))
|
||||||
|
assertTrue(jsonStr.contains("\"retryCount\":3.0"))
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user