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