diff --git a/embrace-android-core/build.gradle.kts b/embrace-android-core/build.gradle.kts
index 42b5da4d67..80a89bba67 100644
--- a/embrace-android-core/build.gradle.kts
+++ b/embrace-android-core/build.gradle.kts
@@ -37,6 +37,7 @@ dependencies {
compileOnly(libs.opentelemetry.semconv.incubating)
implementation(libs.lifecycle.runtime)
implementation(libs.lifecycle.process)
+ implementation(libs.okhttp)
testImplementation(platform(libs.opentelemetry.bom))
testImplementation(libs.opentelemetry.api)
diff --git a/embrace-android-core/config/detekt/baseline.xml b/embrace-android-core/config/detekt/baseline.xml
index f7162bde92..5b94df8f86 100644
--- a/embrace-android-core/config/detekt/baseline.xml
+++ b/embrace-android-core/config/detekt/baseline.xml
@@ -2,6 +2,6 @@
- LongParameterList:DeliveryModuleSupplier.kt$( configModule: ConfigModule, initModule: InitModule, otelModule: OpenTelemetryModule, workerThreadModule: WorkerThreadModule, coreModule: CoreModule, storageModule: StorageModule, essentialServiceModule: EssentialServiceModule, payloadStorageServiceProvider: Provider<PayloadStorageService?>, cacheStorageServiceProvider: Provider<PayloadStorageService?>, requestExecutionServiceProvider: Provider<RequestExecutionService?>, deliveryServiceProvider: Provider<DeliveryService?>, )
+ LongParameterList:DeliveryModuleSupplier.kt$( configModule: ConfigModule, initModule: InitModule, otelModule: OpenTelemetryModule, workerThreadModule: WorkerThreadModule, coreModule: CoreModule, storageModule: StorageModule, essentialServiceModule: EssentialServiceModule, androidServicesModule: AndroidServicesModule, payloadStorageServiceProvider: Provider<PayloadStorageService>?, cacheStorageServiceProvider: Provider<PayloadStorageService>?, requestExecutionServiceProvider: Provider<RequestExecutionService>?, deliveryServiceProvider: Provider<DeliveryService>?, )
diff --git a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/arch/DataCaptureOrchestrator.kt b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/arch/DataCaptureOrchestrator.kt
index 880bb5001c..e3e71caceb 100644
--- a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/arch/DataCaptureOrchestrator.kt
+++ b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/arch/DataCaptureOrchestrator.kt
@@ -1,7 +1,6 @@
package io.embrace.android.embracesdk.internal.arch
import io.embrace.android.embracesdk.internal.arch.datasource.DataSourceState
-import io.embrace.android.embracesdk.internal.config.ConfigService
import io.embrace.android.embracesdk.internal.logging.EmbLogger
import io.embrace.android.embracesdk.internal.logging.InternalErrorType
import io.embrace.android.embracesdk.internal.worker.BackgroundWorker
@@ -12,17 +11,10 @@ import java.util.concurrent.CopyOnWriteArrayList
* place to coordinate everything in one place.
*/
class DataCaptureOrchestrator(
- configService: ConfigService,
private val worker: BackgroundWorker,
private val logger: EmbLogger,
) : EmbraceFeatureRegistry {
- init {
- configService.addListener {
- onConfigChange()
- }
- }
-
private val dataSourceStates = CopyOnWriteArrayList>()
var currentSessionType: SessionType? = null
@@ -38,18 +30,6 @@ class DataCaptureOrchestrator(
}
}
- private fun onConfigChange() {
- dataSourceStates.forEach { state ->
- try {
- state.dispatchStateChange {
- state.onConfigChange()
- }
- } catch (exc: Throwable) {
- logger.trackInternalError(InternalErrorType.CFG_CHANGE_DATA_CAPTURE_FAIL, exc)
- }
- }
- }
-
/**
* Callback that is invoked when the session type changes.
*/
diff --git a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/arch/datasource/DataSourceState.kt b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/arch/datasource/DataSourceState.kt
index d278f42172..707de6f66b 100644
--- a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/arch/datasource/DataSourceState.kt
+++ b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/arch/datasource/DataSourceState.kt
@@ -67,13 +67,6 @@ class DataSourceState>(
}
}
- /**
- * Callback that is invoked when the config layer experiences a change.
- */
- fun onConfigChange() {
- updateDataSource()
- }
-
private fun updateDataSource() {
val enabled =
currentSessionType != null && currentSessionType != disabledSessionType && configGate()
diff --git a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/buildinfo/BuildInfoServiceImpl.kt b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/buildinfo/BuildInfoServiceImpl.kt
index 0fdafdaf5c..7d145565b6 100644
--- a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/buildinfo/BuildInfoServiceImpl.kt
+++ b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/buildinfo/BuildInfoServiceImpl.kt
@@ -2,60 +2,49 @@ package io.embrace.android.embracesdk.internal.buildinfo
import android.content.res.Resources
import io.embrace.android.embracesdk.internal.AndroidResourcesService
-import io.embrace.android.embracesdk.internal.config.instrumented.ProjectConfig
+import io.embrace.android.embracesdk.internal.config.instrumented.schema.InstrumentedConfig
internal class BuildInfoServiceImpl(
- resources: AndroidResourcesService,
- packageName: String,
+ private val instrumentedConfig: InstrumentedConfig,
+ private val resources: AndroidResourcesService,
+ private val packageName: String,
) : BuildInfoService {
+ companion object {
+ private const val BUILD_INFO_RN_BUNDLE_ID: String = "emb_rn_bundle_id"
+ private const val RES_TYPE_STRING = "string"
+ }
+
private val info by lazy {
- fromResources(resources, packageName)
+ BuildInfo(
+ instrumentedConfig.project.getBuildId(),
+ instrumentedConfig.project.getBuildType(),
+ instrumentedConfig.project.getBuildFlavor(),
+ getBuildResource(resources, packageName, BUILD_INFO_RN_BUNDLE_ID),
+ )
}
override fun getBuildInfo(): BuildInfo = info
- companion object {
- private const val BUILD_INFO_RN_BUNDLE_ID: String = "emb_rn_bundle_id"
- private const val RES_TYPE_STRING = "string"
-
- /**
- * Loads the build information from resources provided by the config file packaged within the application by Gradle at
- * build-time.
- *
- * @return the build information
- */
- @JvmStatic
- fun fromResources(resources: AndroidResourcesService, packageName: String): BuildInfo {
- val buildInfo = BuildInfo(
- ProjectConfig.getBuildId(),
- ProjectConfig.getBuildType(),
- ProjectConfig.getBuildFlavor(),
- getBuildResource(resources, packageName, BUILD_INFO_RN_BUNDLE_ID),
+ /**
+ * Given a build property name and a build property type, retrieves the embrace build resource value.
+ */
+ fun getBuildResource(
+ resources: AndroidResourcesService,
+ packageName: String,
+ buildProperty: String,
+ ): String? {
+ return try {
+ val resourceId =
+ resources.getIdentifier(buildProperty, RES_TYPE_STRING, packageName)
+ resources.getString(resourceId)
+ } catch (ex: NullPointerException) {
+ throw IllegalArgumentException(
+ "No resource found for $buildProperty property. Failed to create build info.",
+ ex
)
- return buildInfo
- }
-
- /**
- * Given a build property name and a build property type, retrieves the embrace build resource value.
- */
- fun getBuildResource(
- resources: AndroidResourcesService,
- packageName: String,
- buildProperty: String,
- ): String? {
- return try {
- val resourceId =
- resources.getIdentifier(buildProperty, RES_TYPE_STRING, packageName)
- resources.getString(resourceId)
- } catch (ex: NullPointerException) {
- throw IllegalArgumentException(
- "No resource found for $buildProperty property. Failed to create build info.",
- ex
- )
- } catch (ex: Resources.NotFoundException) {
- null
- }
+ } catch (ex: Resources.NotFoundException) {
+ null
}
}
}
diff --git a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/comms/api/ApiRequestMapper.kt b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/comms/api/ApiRequestMapper.kt
index 8f6b40db0b..bccd822c6c 100644
--- a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/comms/api/ApiRequestMapper.kt
+++ b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/comms/api/ApiRequestMapper.kt
@@ -13,7 +13,7 @@ internal class ApiRequestMapper(
) {
private val apiUrlBuilders = Endpoint.values().associateWith {
- urlBuilder.getEmbraceUrlWithSuffix(it.version, it.path)
+ urlBuilder.resolveUrl(it)
}
private fun Endpoint.asEmbraceUrl(): String = checkNotNull(apiUrlBuilders[this])
diff --git a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/comms/api/ApiResponseCache.kt b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/comms/api/ApiResponseCache.kt
deleted file mode 100644
index 1a57e311b3..0000000000
--- a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/comms/api/ApiResponseCache.kt
+++ /dev/null
@@ -1,95 +0,0 @@
-package io.embrace.android.embracesdk.internal.comms.api
-
-import android.net.http.HttpResponseCache
-import io.embrace.android.embracesdk.internal.config.remote.RemoteConfig
-import io.embrace.android.embracesdk.internal.serialization.PlatformSerializer
-import io.embrace.android.embracesdk.internal.storage.StorageService
-import java.io.Closeable
-import java.io.IOException
-import java.net.CacheResponse
-import java.net.URI
-import java.util.zip.GZIPInputStream
-
-/**
- * Caches HTTP requests made via HttpUrlConnection using [HttpResponseCache]. This is
- * currently only used to cache responses from the config endpoint, which contain etags in the
- * response headers.
- *
- * This class therefore provides functions to retrieve the etag for any cached responses. This
- * means the eTag can be set in the request header & we can avoid unnecessary work on the client
- * & on the server.
- */
-class ApiResponseCache(
- private val serializer: PlatformSerializer,
- private val storageService: StorageService,
-) : Closeable {
-
- private companion object {
- private const val MAX_CACHE_SIZE_BYTES: Long = 2 * 1024 * 1024 // 2 MiB
- private const val ETAG_HEADER = "ETag"
- }
-
- @Volatile
- private var cache: HttpResponseCache? = null
- private val lock = Object()
-
- private fun initializeIfNeeded() {
- if (cache == null) {
- synchronized(lock) {
- if (cache == null) {
- cache = runCatching {
- HttpResponseCache.install(
- storageService.getConfigCacheDir(),
- MAX_CACHE_SIZE_BYTES
- )
- }.getOrNull()
- }
- }
- }
- }
-
- override fun close() {
- cache?.flush()
- }
-
- fun retrieveCachedConfig(url: String, request: ApiRequest): CachedConfig {
- val cachedResponse = retrieveCacheResponse(url, request)
- val obj = cachedResponse?.runCatching {
- GZIPInputStream(body).use {
- serializer.fromJson(it, RemoteConfig::class.java)
- }
- }?.getOrNull()
- val eTag = cachedResponse?.let { retrieveETag(cachedResponse) }
- return CachedConfig(obj, eTag)
- }
-
- /**
- * Retrieves the cache response for the given request, if any exists.
- */
- private fun retrieveCacheResponse(url: String, request: ApiRequest): CacheResponse? {
- initializeIfNeeded()
- val obj = cache ?: return null
-
- return try {
- val uri = URI.create(url)
- val requestMethod = request.httpMethod.toString()
- val headerFields = request.getHeaders().mapValues { listOf(it.value) }
- obj.get(uri, requestMethod, headerFields)
- } catch (exc: IOException) {
- null
- }
- }
-
- /**
- * Searches the cache to see whether a request has a cached response, and if so returns its etag.
- */
- private fun retrieveETag(cacheResponse: CacheResponse): String? {
- runCatching {
- val eTag = cacheResponse.headers[ETAG_HEADER]
- if (!eTag.isNullOrEmpty()) {
- return eTag[0]
- }
- }
- return null
- }
-}
diff --git a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/comms/api/ApiService.kt b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/comms/api/ApiService.kt
index e0269036ba..b84009f5cf 100644
--- a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/comms/api/ApiService.kt
+++ b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/comms/api/ApiService.kt
@@ -1,13 +1,12 @@
package io.embrace.android.embracesdk.internal.comms.api
import io.embrace.android.embracesdk.internal.capture.connectivity.NetworkConnectivityListener
-import io.embrace.android.embracesdk.internal.config.RemoteConfigSource
import io.embrace.android.embracesdk.internal.injection.SerializationAction
import io.embrace.android.embracesdk.internal.payload.Envelope
import io.embrace.android.embracesdk.internal.payload.LogPayload
import java.util.concurrent.Future
-interface ApiService : RemoteConfigSource, NetworkConnectivityListener {
+interface ApiService : NetworkConnectivityListener {
/**
* Sends a list of OTel Logs to the API.
diff --git a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/comms/api/ApiUrlBuilder.kt b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/comms/api/ApiUrlBuilder.kt
index 3425794a53..85f7b47b90 100644
--- a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/comms/api/ApiUrlBuilder.kt
+++ b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/comms/api/ApiUrlBuilder.kt
@@ -6,12 +6,22 @@ package io.embrace.android.embracesdk.internal.comms.api
interface ApiUrlBuilder {
/**
- * Returns the url used to fetch the config.
+ * The App ID that will be used in API requests.
*/
- fun getConfigUrl(): String
+ val appId: String
+
+ /**
+ * The Device ID that will be used in API requests.
+ */
+ val deviceId: String
+
+ /**
+ * Base URL for the data endpoint
+ */
+ val baseDataUrl: String
/**
* Returns the url used to send data to Embrace.
*/
- fun getEmbraceUrlWithSuffix(apiVersion: String, suffix: String): String
+ fun resolveUrl(endpoint: Endpoint): String
}
diff --git a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/comms/api/EmbraceApiService.kt b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/comms/api/EmbraceApiService.kt
index 1c7ba875f2..7ab5df10b7 100644
--- a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/comms/api/EmbraceApiService.kt
+++ b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/comms/api/EmbraceApiService.kt
@@ -1,25 +1,21 @@
package io.embrace.android.embracesdk.internal.comms.api
-import io.embrace.android.embracesdk.core.BuildConfig
import io.embrace.android.embracesdk.internal.Systrace
import io.embrace.android.embracesdk.internal.TypeUtils
import io.embrace.android.embracesdk.internal.comms.delivery.NetworkStatus
import io.embrace.android.embracesdk.internal.comms.delivery.PendingApiCallsSender
import io.embrace.android.embracesdk.internal.compression.ConditionalGzipOutputStream
-import io.embrace.android.embracesdk.internal.config.remote.RemoteConfig
import io.embrace.android.embracesdk.internal.injection.SerializationAction
import io.embrace.android.embracesdk.internal.payload.Envelope
import io.embrace.android.embracesdk.internal.payload.LogPayload
import io.embrace.android.embracesdk.internal.serialization.PlatformSerializer
import io.embrace.android.embracesdk.internal.worker.PriorityWorker
-import io.embrace.android.embracesdk.network.http.HttpMethod
import java.lang.reflect.ParameterizedType
import java.util.concurrent.Future
internal class EmbraceApiService(
private val apiClient: ApiClient,
private val serializer: PlatformSerializer,
- private val cachedConfigProvider: (url: String, request: ApiRequest) -> CachedConfig,
private val priorityWorker: PriorityWorker,
private val pendingApiCallsSender: PendingApiCallsSender,
lazyDeviceId: Lazy,
@@ -32,11 +28,6 @@ internal class EmbraceApiService(
ApiRequestMapper(urlBuilder, lazyDeviceId, appId)
}
}
- private val configUrl by lazy {
- Systrace.traceSynchronous("config-url-init") {
- urlBuilder.getConfigUrl()
- }
- }
private var lastNetworkStatus: NetworkStatus = NetworkStatus.UNKNOWN
init {
@@ -45,60 +36,6 @@ internal class EmbraceApiService(
}
}
- @Throws(IllegalStateException::class)
- @Suppress("UseCheckOrError")
- override fun getConfig(): RemoteConfig? {
- var request = prepareConfigRequest(configUrl)
- val cachedResponse = cachedConfigProvider(configUrl, request)
- if (cachedResponse.isValid()) { // only bother if we have a useful response.
- request = request.copy(eTag = cachedResponse.eTag)
- }
-
- return when (val response = apiClient.executeGet(request)) {
- is ApiResponse.Success -> {
- response.body?.let {
- serializer.fromJson(it, RemoteConfig::class.java)
- }
- }
-
- is ApiResponse.NotModified -> {
- cachedResponse.remoteConfig
- }
-
- is ApiResponse.TooManyRequests -> {
- // TODO: We should retry after the retryAfter time or 3 seconds and apply exponential backoff.
- null
- }
-
- is ApiResponse.Failure, ApiResponse.None, ApiResponse.NoPayload -> {
- null
- }
-
- is ApiResponse.Incomplete -> {
- throw response.exception
- }
-
- ApiResponse.PayloadTooLarge -> {
- // Not expected to receive a 413 response for a GET request.
- null
- }
- }
- }
-
- override fun getCachedConfig(): CachedConfig {
- val request = prepareConfigRequest(configUrl)
- return cachedConfigProvider(configUrl, request)
- }
-
- private fun prepareConfigRequest(url: String) = ApiRequest(
- contentType = "application/json",
- userAgent = "Embrace/a/" + BuildConfig.VERSION_NAME,
- accept = "application/json",
- url = ApiRequestUrl(url),
- httpMethod = HttpMethod.GET,
- acceptEncoding = "gzip",
- )
-
override fun onNetworkConnectivityStatusChanged(status: NetworkStatus) {
lastNetworkStatus = status
}
diff --git a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/comms/api/EmbraceApiUrlBuilder.kt b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/comms/api/EmbraceApiUrlBuilder.kt
index 1fded563a5..379e065281 100644
--- a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/comms/api/EmbraceApiUrlBuilder.kt
+++ b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/comms/api/EmbraceApiUrlBuilder.kt
@@ -1,29 +1,36 @@
package io.embrace.android.embracesdk.internal.comms.api
import android.os.Build
+import io.embrace.android.embracesdk.internal.config.instrumented.schema.InstrumentedConfig
internal class EmbraceApiUrlBuilder(
- private val coreBaseUrl: String,
- private val configBaseUrl: String,
- private val appId: String,
- private val lazyDeviceId: Lazy,
- private val lazyAppVersionName: Lazy,
+ override val deviceId: String,
+ private val appVersionName: String,
+ instrumentedConfig: InstrumentedConfig,
) : ApiUrlBuilder {
+
companion object {
- private const val CONFIG_API_VERSION = 2
+ private const val CONFIG_DEFAULT: String = "config.emb-api.com"
+ private const val DATA_DEFAULT: String = "data.emb-api.com"
}
- private fun getConfigBaseUrl() = "$configBaseUrl/v$CONFIG_API_VERSION/${"config"}"
-
- private fun getOperatingSystemCode() = Build.VERSION.SDK_INT.toString() + ".0.0"
-
- override fun getConfigUrl(): String {
- return "${getConfigBaseUrl()}?appId=$appId&osVersion=${getOperatingSystemCode()}" +
- "&appVersion=${lazyAppVersionName.value}&deviceId=${lazyDeviceId.value}"
- }
+ override val appId: String = checkNotNull(instrumentedConfig.project.getAppId())
+ private val coreBaseUrl = instrumentedConfig.baseUrls.getData() ?: "https://a-$appId.$DATA_DEFAULT"
+ private val configBaseUrl = instrumentedConfig.baseUrls.getConfig() ?: "https://a-$appId.$CONFIG_DEFAULT"
+ private val operatingSystemCode = Build.VERSION.SDK_INT.toString() + ".0.0"
+ override val baseDataUrl: String = resolveUrl(Endpoint.SESSIONS).split(Endpoint.SESSIONS.path).first()
- override fun getEmbraceUrlWithSuffix(apiVersion: String, suffix: String): String {
- val fullSuffix = if (apiVersion == "v1") "log/$suffix" else suffix
- return "$coreBaseUrl/$apiVersion/$fullSuffix"
+ override fun resolveUrl(endpoint: Endpoint): String {
+ val baseUrl = when (endpoint) {
+ Endpoint.CONFIG -> configBaseUrl
+ else -> coreBaseUrl
+ }
+ val queryParams = when (endpoint) {
+ Endpoint.CONFIG ->
+ "?appId=$appId&osVersion=$operatingSystemCode" +
+ "&appVersion=$appVersionName&deviceId=$deviceId"
+ else -> ""
+ }
+ return "$baseUrl/${endpoint.version}/${endpoint.path}$queryParams"
}
}
diff --git a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/comms/api/EmbraceUrl.kt b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/comms/api/EmbraceUrl.kt
index 45ec98f1a9..db25dbe087 100644
--- a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/comms/api/EmbraceUrl.kt
+++ b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/comms/api/EmbraceUrl.kt
@@ -18,6 +18,7 @@ internal class EmbraceUrl(val url: URL) {
return when (url.path.substringAfterLast("/")) {
Endpoint.LOGS.path -> Endpoint.LOGS
Endpoint.SESSIONS.path -> Endpoint.SESSIONS
+ Endpoint.CONFIG.path -> Endpoint.CONFIG
else -> Endpoint.UNKNOWN
}
}
diff --git a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/comms/delivery/PendingApiCallQueue.kt b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/comms/delivery/PendingApiCallQueue.kt
index f68f776c7e..2e506c2876 100644
--- a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/comms/delivery/PendingApiCallQueue.kt
+++ b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/comms/delivery/PendingApiCallQueue.kt
@@ -88,7 +88,7 @@ class PendingApiCallQueue(
return when (this) {
Endpoint.LOGS -> 10
Endpoint.SESSIONS -> 100
- Endpoint.UNKNOWN -> 50
+ else -> 50
}
}
}
diff --git a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/ConfigService.kt b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/ConfigService.kt
index 14b688cc09..0995e588bc 100644
--- a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/ConfigService.kt
+++ b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/ConfigService.kt
@@ -9,7 +9,6 @@ import io.embrace.android.embracesdk.internal.config.behavior.DataCaptureEventBe
import io.embrace.android.embracesdk.internal.config.behavior.LogMessageBehavior
import io.embrace.android.embracesdk.internal.config.behavior.NetworkBehavior
import io.embrace.android.embracesdk.internal.config.behavior.NetworkSpanForwardingBehavior
-import io.embrace.android.embracesdk.internal.config.behavior.SdkEndpointBehavior
import io.embrace.android.embracesdk.internal.config.behavior.SdkModeBehavior
import io.embrace.android.embracesdk.internal.config.behavior.SensitiveKeysBehavior
import io.embrace.android.embracesdk.internal.config.behavior.SessionBehavior
@@ -23,8 +22,6 @@ import io.embrace.android.embracesdk.internal.payload.AppFramework
*/
interface ConfigService {
- var remoteConfigSource: RemoteConfigSource?
-
/**
* How background activity functionality should behave.
*/
@@ -70,11 +67,6 @@ interface ConfigService {
*/
val sdkModeBehavior: SdkModeBehavior
- /**
- * Provides base endpoints the SDK should send data to
- */
- val sdkEndpointBehavior: SdkEndpointBehavior
-
/**
* Provides whether the SDK should enable certain 'behavior' of web vitals
*/
@@ -111,49 +103,4 @@ interface ConfigService {
* to Embrace).
*/
fun isOnlyUsingOtelExporters(): Boolean
-
- /**
- * Adds a listener for changes to the [RemoteConfig]. The listeners will be notified when the
- * [ConfigService] refreshes its configuration.
- *
- * @param configListener the listener to add
- */
- fun addListener(configListener: () -> Unit)
-
- /**
- * Checks if the SDK is enabled.
- *
- * The SDK can be configured to disable a percentage of devices based on the normalization of
- * their device ID between 1-100. This threshold is set in [RemoteConfig].
- *
- * @return true if the sdk is enabled, false otherwise
- */
- fun isSdkDisabled(): Boolean
-
- /**
- * Checks if the capture of background activity is enabled.
- *
- *
- * The background activity capture can be configured to enable a percentage of
- * devices based on the normalization of their device ID between 1-100.
- *
- * @return true if background activity capture is enabled.
- */
- fun isBackgroundActivityCaptureEnabled(): Boolean
-
- /**
- * Returns true if the remote config has been fetched and is not expired. Generally speaking
- * use of this function should be discouraged - but it can be useful to prevent running risky
- * behavior that should only be switched on via remote config.
- *
- * Most callers will not need this function - try not to abuse it.
- */
- fun hasValidRemoteConfig(): Boolean
-
- /**
- * Checks if the capture of Application Exit Info is enabled.
- *
- * @return true if AEI capture is enabled.
- */
- fun isAppExitInfoCaptureEnabled(): Boolean
}
diff --git a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/ConfigServiceImpl.kt b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/ConfigServiceImpl.kt
new file mode 100644
index 0000000000..24a82b3ccb
--- /dev/null
+++ b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/ConfigServiceImpl.kt
@@ -0,0 +1,73 @@
+package io.embrace.android.embracesdk.internal.config
+
+import io.embrace.android.embracesdk.internal.config.behavior.AnrBehaviorImpl
+import io.embrace.android.embracesdk.internal.config.behavior.AppExitInfoBehaviorImpl
+import io.embrace.android.embracesdk.internal.config.behavior.AutoDataCaptureBehaviorImpl
+import io.embrace.android.embracesdk.internal.config.behavior.BackgroundActivityBehaviorImpl
+import io.embrace.android.embracesdk.internal.config.behavior.BehaviorThresholdCheck
+import io.embrace.android.embracesdk.internal.config.behavior.BreadcrumbBehaviorImpl
+import io.embrace.android.embracesdk.internal.config.behavior.DataCaptureEventBehaviorImpl
+import io.embrace.android.embracesdk.internal.config.behavior.LogMessageBehaviorImpl
+import io.embrace.android.embracesdk.internal.config.behavior.NetworkBehaviorImpl
+import io.embrace.android.embracesdk.internal.config.behavior.NetworkSpanForwardingBehaviorImpl
+import io.embrace.android.embracesdk.internal.config.behavior.SdkModeBehaviorImpl
+import io.embrace.android.embracesdk.internal.config.behavior.SensitiveKeysBehaviorImpl
+import io.embrace.android.embracesdk.internal.config.behavior.SessionBehaviorImpl
+import io.embrace.android.embracesdk.internal.config.behavior.WebViewVitalsBehaviorImpl
+import io.embrace.android.embracesdk.internal.config.instrumented.schema.InstrumentedConfig
+import io.embrace.android.embracesdk.internal.config.remote.RemoteConfig
+import io.embrace.android.embracesdk.internal.opentelemetry.OpenTelemetryConfiguration
+import io.embrace.android.embracesdk.internal.payload.AppFramework
+import io.embrace.android.embracesdk.internal.prefs.PreferencesService
+
+/**
+ * Loads configuration for the app from the Embrace API.
+ */
+internal class ConfigServiceImpl(
+ openTelemetryCfg: OpenTelemetryConfiguration,
+ preferencesService: PreferencesService,
+ suppliedFramework: AppFramework,
+ instrumentedConfig: InstrumentedConfig,
+ remoteConfig: RemoteConfig?,
+ thresholdCheck: BehaviorThresholdCheck = BehaviorThresholdCheck { preferencesService.deviceIdentifier },
+) : ConfigService {
+
+ override val backgroundActivityBehavior =
+ BackgroundActivityBehaviorImpl(thresholdCheck, instrumentedConfig, remoteConfig)
+ override val autoDataCaptureBehavior = AutoDataCaptureBehaviorImpl(thresholdCheck, instrumentedConfig, remoteConfig)
+ override val breadcrumbBehavior = BreadcrumbBehaviorImpl(instrumentedConfig, remoteConfig)
+ override val sensitiveKeysBehavior = SensitiveKeysBehaviorImpl(instrumentedConfig)
+ override val logMessageBehavior = LogMessageBehaviorImpl(remoteConfig)
+ override val anrBehavior = AnrBehaviorImpl(thresholdCheck, instrumentedConfig, remoteConfig)
+ override val sessionBehavior = SessionBehaviorImpl(instrumentedConfig, remoteConfig)
+ override val networkBehavior = NetworkBehaviorImpl(instrumentedConfig, remoteConfig)
+ override val dataCaptureEventBehavior = DataCaptureEventBehaviorImpl(remoteConfig)
+ override val sdkModeBehavior = SdkModeBehaviorImpl(thresholdCheck, remoteConfig)
+ override val appExitInfoBehavior = AppExitInfoBehaviorImpl(thresholdCheck, instrumentedConfig, remoteConfig)
+ override val webViewVitalsBehavior = WebViewVitalsBehaviorImpl(thresholdCheck, remoteConfig)
+ override val networkSpanForwardingBehavior =
+ NetworkSpanForwardingBehaviorImpl(thresholdCheck, instrumentedConfig, remoteConfig)
+
+ override val appId: String? = resolveAppId(instrumentedConfig.project.getAppId(), openTelemetryCfg)
+
+ override fun isOnlyUsingOtelExporters(): Boolean = appId.isNullOrEmpty()
+
+ /**
+ * Loads the build information from resources provided by the config file packaged within the application by Gradle at
+ * build-time.
+ *
+ * @return the local configuration
+ */
+ fun resolveAppId(id: String?, openTelemetryCfg: OpenTelemetryConfiguration): String? {
+ require(!id.isNullOrEmpty() || openTelemetryCfg.hasConfiguredOtelExporters()) {
+ "No appId supplied in embrace-config.json. This is required if you want to " +
+ "send data to Embrace, unless you configure an OTel exporter and add" +
+ " embrace.disableMappingFileUpload=true to gradle.properties."
+ }
+ return id
+ }
+
+ override val appFramework: AppFramework = instrumentedConfig.project.getAppFramework()?.let {
+ AppFramework.fromString(it)
+ } ?: suppliedFramework
+}
diff --git a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/EmbraceConfigService.kt b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/EmbraceConfigService.kt
deleted file mode 100644
index e0e32ac9fe..0000000000
--- a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/EmbraceConfigService.kt
+++ /dev/null
@@ -1,330 +0,0 @@
-package io.embrace.android.embracesdk.internal.config
-
-import io.embrace.android.embracesdk.internal.clock.Clock
-import io.embrace.android.embracesdk.internal.config.behavior.AnrBehavior
-import io.embrace.android.embracesdk.internal.config.behavior.AnrBehaviorImpl
-import io.embrace.android.embracesdk.internal.config.behavior.AppExitInfoBehavior
-import io.embrace.android.embracesdk.internal.config.behavior.AppExitInfoBehaviorImpl
-import io.embrace.android.embracesdk.internal.config.behavior.AutoDataCaptureBehavior
-import io.embrace.android.embracesdk.internal.config.behavior.AutoDataCaptureBehaviorImpl
-import io.embrace.android.embracesdk.internal.config.behavior.BackgroundActivityBehavior
-import io.embrace.android.embracesdk.internal.config.behavior.BackgroundActivityBehaviorImpl
-import io.embrace.android.embracesdk.internal.config.behavior.BehaviorThresholdCheck
-import io.embrace.android.embracesdk.internal.config.behavior.BreadcrumbBehavior
-import io.embrace.android.embracesdk.internal.config.behavior.BreadcrumbBehaviorImpl
-import io.embrace.android.embracesdk.internal.config.behavior.DataCaptureEventBehavior
-import io.embrace.android.embracesdk.internal.config.behavior.DataCaptureEventBehaviorImpl
-import io.embrace.android.embracesdk.internal.config.behavior.LogMessageBehavior
-import io.embrace.android.embracesdk.internal.config.behavior.LogMessageBehaviorImpl
-import io.embrace.android.embracesdk.internal.config.behavior.NetworkBehavior
-import io.embrace.android.embracesdk.internal.config.behavior.NetworkBehaviorImpl
-import io.embrace.android.embracesdk.internal.config.behavior.NetworkSpanForwardingBehavior
-import io.embrace.android.embracesdk.internal.config.behavior.NetworkSpanForwardingBehaviorImpl
-import io.embrace.android.embracesdk.internal.config.behavior.SdkEndpointBehavior
-import io.embrace.android.embracesdk.internal.config.behavior.SdkEndpointBehaviorImpl
-import io.embrace.android.embracesdk.internal.config.behavior.SdkModeBehavior
-import io.embrace.android.embracesdk.internal.config.behavior.SdkModeBehaviorImpl
-import io.embrace.android.embracesdk.internal.config.behavior.SensitiveKeysBehavior
-import io.embrace.android.embracesdk.internal.config.behavior.SensitiveKeysBehaviorImpl
-import io.embrace.android.embracesdk.internal.config.behavior.SessionBehavior
-import io.embrace.android.embracesdk.internal.config.behavior.SessionBehaviorImpl
-import io.embrace.android.embracesdk.internal.config.behavior.WebViewVitalsBehavior
-import io.embrace.android.embracesdk.internal.config.behavior.WebViewVitalsBehaviorImpl
-import io.embrace.android.embracesdk.internal.config.instrumented.InstrumentedConfig
-import io.embrace.android.embracesdk.internal.config.remote.RemoteConfig
-import io.embrace.android.embracesdk.internal.logging.EmbLogger
-import io.embrace.android.embracesdk.internal.logging.InternalErrorType
-import io.embrace.android.embracesdk.internal.opentelemetry.OpenTelemetryConfiguration
-import io.embrace.android.embracesdk.internal.payload.AppFramework
-import io.embrace.android.embracesdk.internal.prefs.PreferencesService
-import io.embrace.android.embracesdk.internal.session.lifecycle.ProcessStateListener
-import io.embrace.android.embracesdk.internal.utils.Provider
-import io.embrace.android.embracesdk.internal.utils.stream
-import io.embrace.android.embracesdk.internal.worker.BackgroundWorker
-import java.util.concurrent.CopyOnWriteArraySet
-import kotlin.math.min
-
-/**
- * Loads configuration for the app from the Embrace API.
- */
-internal class EmbraceConfigService(
- openTelemetryCfg: OpenTelemetryConfiguration,
- private val preferencesService: PreferencesService,
- private val clock: Clock,
- private val logger: EmbLogger,
- private val backgroundWorker: BackgroundWorker,
- suppliedFramework: AppFramework,
- private val foregroundAction: ConfigService.() -> Unit,
- appIdFromConfig: String?,
- val thresholdCheck: BehaviorThresholdCheck =
- BehaviorThresholdCheck { preferencesService.deviceIdentifier },
-) : ConfigService, ProcessStateListener {
-
- /**
- * The listeners subscribed to configuration changes.
- */
- private val listeners: MutableSet<() -> Unit> = CopyOnWriteArraySet()
- private val lock = Any()
- override var remoteConfigSource: RemoteConfigSource? = null
- set(value) {
- field = value
- loadConfigFromCache()
- attemptConfigRefresh()
- }
-
- @Volatile
- private var configProp = RemoteConfig()
-
- @Volatile
- var lastUpdated: Long = 0
-
- @Volatile
- private var lastRefreshConfigAttempt: Long = 0
-
- @Volatile
- private var configRetrySafeWindow = DEFAULT_RETRY_WAIT_TIME.toDouble()
-
- private val remoteSupplier: Provider = { getConfig() }
-
- override val backgroundActivityBehavior: BackgroundActivityBehavior =
- BackgroundActivityBehaviorImpl(
- thresholdCheck = thresholdCheck,
- remoteSupplier = { getConfig().backgroundActivityConfig }
- )
-
- override val autoDataCaptureBehavior: AutoDataCaptureBehavior =
- AutoDataCaptureBehaviorImpl(
- thresholdCheck = thresholdCheck,
- remoteSupplier = remoteSupplier
- )
-
- override val breadcrumbBehavior: BreadcrumbBehavior =
- BreadcrumbBehaviorImpl(
- thresholdCheck,
- remoteSupplier = remoteSupplier
- )
-
- override val sensitiveKeysBehavior: SensitiveKeysBehavior = SensitiveKeysBehaviorImpl()
-
- override val logMessageBehavior: LogMessageBehavior =
- LogMessageBehaviorImpl(
- thresholdCheck,
- remoteSupplier = { getConfig().logConfig }
- )
-
- override val anrBehavior: AnrBehavior =
- AnrBehaviorImpl(
- thresholdCheck,
- remoteSupplier = { getConfig().anrConfig }
- )
-
- override val sessionBehavior: SessionBehavior = SessionBehaviorImpl(
- thresholdCheck,
- remoteSupplier = { getConfig() }
- )
-
- override val networkBehavior: NetworkBehavior =
- NetworkBehaviorImpl(
- thresholdCheck = thresholdCheck,
- remoteSupplier = remoteSupplier
- )
-
- override val dataCaptureEventBehavior: DataCaptureEventBehavior = DataCaptureEventBehaviorImpl(
- thresholdCheck = thresholdCheck,
- remoteSupplier = remoteSupplier
- )
-
- override val sdkModeBehavior: SdkModeBehavior = SdkModeBehaviorImpl(
- thresholdCheck = thresholdCheck,
- remoteSupplier = remoteSupplier
- )
-
- override val sdkEndpointBehavior: SdkEndpointBehavior = SdkEndpointBehaviorImpl(
- thresholdCheck = thresholdCheck
- )
-
- override val appExitInfoBehavior: AppExitInfoBehavior = AppExitInfoBehaviorImpl(
- thresholdCheck = thresholdCheck,
- remoteSupplier = remoteSupplier
- )
-
- override val networkSpanForwardingBehavior: NetworkSpanForwardingBehavior =
- NetworkSpanForwardingBehaviorImpl(
- thresholdCheck = thresholdCheck,
- remoteSupplier = { getConfig().networkSpanForwardingRemoteConfig }
- )
-
- override val webViewVitalsBehavior: WebViewVitalsBehavior =
- WebViewVitalsBehaviorImpl(
- thresholdCheck = thresholdCheck,
- remoteSupplier = remoteSupplier
- )
-
- override val appId: String? = resolveAppId(appIdFromConfig, openTelemetryCfg)
-
- override fun isOnlyUsingOtelExporters(): Boolean = appId.isNullOrEmpty()
-
- /**
- * Loads the build information from resources provided by the config file packaged within the application by Gradle at
- * build-time.
- *
- * @return the local configuration
- */
- fun resolveAppId(id: String?, openTelemetryCfg: OpenTelemetryConfiguration): String? {
- require(!id.isNullOrEmpty() || openTelemetryCfg.hasConfiguredOtelExporters()) {
- "No appId supplied in embrace-config.json. This is required if you want to " +
- "send data to Embrace, unless you configure an OTel exporter and add" +
- " embrace.disableMappingFileUpload=true to gradle.properties."
- }
- return id
- }
-
- /**
- * Load Config from cache if present.
- */
- fun loadConfigFromCache() {
- val cachedConfig = remoteConfigSource?.getCachedConfig()
- val obj = cachedConfig?.remoteConfig
-
- if (obj != null) {
- val oldConfig = configProp
- updateConfig(oldConfig, obj)
- }
- }
-
- private fun getConfig(): RemoteConfig {
- attemptConfigRefresh()
- return configProp
- }
-
- private fun attemptConfigRefresh() {
- if (configRequiresRefresh() && configRetryIsSafe()) {
- synchronized(lock) {
- if (configRequiresRefresh() && configRetryIsSafe()) {
- lastRefreshConfigAttempt = clock.now()
- // Attempt to asynchronously update the config if it is out of date
- refreshConfig()
- }
- }
- }
- }
-
- private fun refreshConfig() {
- val previousConfig = configProp
- backgroundWorker.submit {
- // Ensure that another thread didn't refresh it already in the meantime
- if (configRequiresRefresh()) {
- try {
- lastRefreshConfigAttempt = clock.now()
- val newConfig = remoteConfigSource?.getConfig()
- if (newConfig != null) {
- updateConfig(previousConfig, newConfig)
- lastUpdated = clock.now()
- }
- configRetrySafeWindow = DEFAULT_RETRY_WAIT_TIME.toDouble()
- } catch (ex: Exception) {
- configRetrySafeWindow =
- min(
- MAX_ALLOWED_RETRY_WAIT_TIME.toDouble(),
- configRetrySafeWindow * 2
- )
- }
- }
- }
- }
-
- private fun updateConfig(previousConfig: RemoteConfig, newConfig: RemoteConfig) {
- val b = newConfig != previousConfig
- if (b) {
- configProp = newConfig
- persistConfig()
- // Only notify listeners if the config has actually changed value
- notifyListeners()
- }
- }
-
- private fun persistConfig() {
- // TODO: future get rid of these prefs from PrefService entirely?
- preferencesService.sdkDisabled = sdkModeBehavior.isSdkDisabled()
- preferencesService.backgroundActivityEnabled =
- backgroundActivityBehavior.isBackgroundActivityCaptureEnabled()
- }
-
- // TODO: future extract these out to SdkBehavior interface
- override fun isSdkDisabled(): Boolean {
- return preferencesService.sdkDisabled
- }
-
- override fun isBackgroundActivityCaptureEnabled(): Boolean {
- return preferencesService.backgroundActivityEnabled
- }
-
- override fun addListener(configListener: () -> Unit) {
- listeners.add(configListener)
- }
-
- override fun onForeground(coldStart: Boolean, timestamp: Long) {
- // Refresh the config on resume if it has expired
- getConfig()
- foregroundAction()
- }
-
- override val appFramework: AppFramework = InstrumentedConfig.project.getAppFramework()?.let {
- AppFramework.fromString(it)
- } ?: suppliedFramework
-
- /**
- * Notifies the listeners that a new config was fetched from the server.
- */
- private fun notifyListeners() {
- stream(listeners) { listener ->
- try {
- listener()
- } catch (ex: Exception) {
- logger.trackInternalError(InternalErrorType.CONFIG_LISTENER_FAIL, ex)
- }
- }
- }
-
- /**
- * Checks if the time diff since the last fetch exceeds the
- * [EmbraceConfigService.CONFIG_TTL] millis.
- *
- * @return if the config requires to be fetched from the remote server again or not.
- */
- private fun configRequiresRefresh(): Boolean {
- return clock.now() - lastUpdated > CONFIG_TTL
- }
-
- /**
- * Checks if the time diff since the last attempt is enough to try again.
- *
- * @return if the config can be fetched from the remote server again or not.
- */
- private fun configRetryIsSafe(): Boolean {
- return clock.now() > lastRefreshConfigAttempt + configRetrySafeWindow * 1000
- }
-
- override fun hasValidRemoteConfig(): Boolean = !configRequiresRefresh()
- override fun isAppExitInfoCaptureEnabled(): Boolean {
- return appExitInfoBehavior.isAeiCaptureEnabled()
- }
-
- private companion object {
-
- /**
- * Config lives for 1 hour before attempting to retrieve again.
- */
- private const val CONFIG_TTL = 60 * 60 * 1000L
-
- /**
- * Config refresh default retry period.
- */
- private const val DEFAULT_RETRY_WAIT_TIME: Long = 20 // 20 seconds
-
- /**
- * Config max allowed refresh retry period.
- */
- private const val MAX_ALLOWED_RETRY_WAIT_TIME: Long = 300 // 5 minutes
- }
-}
diff --git a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/RemoteConfigSource.kt b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/RemoteConfigSource.kt
deleted file mode 100644
index 2fd1aadad5..0000000000
--- a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/RemoteConfigSource.kt
+++ /dev/null
@@ -1,19 +0,0 @@
-package io.embrace.android.embracesdk.internal.config
-
-import io.embrace.android.embracesdk.internal.comms.api.CachedConfig
-import io.embrace.android.embracesdk.internal.config.remote.RemoteConfig
-
-interface RemoteConfigSource {
-
- /**
- * Asynchronously gets the app's SDK configuration.
- *
- * These settings define app-specific settings, such as disabled log patterns, whether
- * screenshots are enabled, as well as limits and thresholds.
- *
- * @return a future containing the configuration.
- */
- fun getConfig(): RemoteConfig?
-
- fun getCachedConfig(): CachedConfig
-}
diff --git a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/behavior/AnrBehavior.kt b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/behavior/AnrBehavior.kt
index 9e605a0492..4e52db4b4d 100644
--- a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/behavior/AnrBehavior.kt
+++ b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/behavior/AnrBehavior.kt
@@ -1,9 +1,11 @@
package io.embrace.android.embracesdk.internal.config.behavior
+import io.embrace.android.embracesdk.internal.config.instrumented.schema.EnabledFeatureConfig
import io.embrace.android.embracesdk.internal.config.remote.AllowedNdkSampleMethod
+import io.embrace.android.embracesdk.internal.config.remote.AnrRemoteConfig
import io.embrace.android.embracesdk.internal.config.remote.Unwinder
-interface AnrBehavior {
+interface AnrBehavior : ConfigBehavior {
/**
* Percentage of users for which ANR stack trace capture is enabled.
diff --git a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/behavior/AnrBehaviorImpl.kt b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/behavior/AnrBehaviorImpl.kt
index 02b2f5e5e7..fc956976c9 100644
--- a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/behavior/AnrBehaviorImpl.kt
+++ b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/behavior/AnrBehaviorImpl.kt
@@ -1,22 +1,18 @@
package io.embrace.android.embracesdk.internal.config.behavior
-import io.embrace.android.embracesdk.internal.config.UnimplementedConfig
-import io.embrace.android.embracesdk.internal.config.instrumented.InstrumentedConfig
+import io.embrace.android.embracesdk.internal.config.instrumented.schema.InstrumentedConfig
import io.embrace.android.embracesdk.internal.config.remote.AllowedNdkSampleMethod
-import io.embrace.android.embracesdk.internal.config.remote.AnrRemoteConfig
+import io.embrace.android.embracesdk.internal.config.remote.RemoteConfig
import io.embrace.android.embracesdk.internal.config.remote.Unwinder
-import io.embrace.android.embracesdk.internal.utils.Provider
/**
* Provides the behavior that the ANR feature should follow.
*/
class AnrBehaviorImpl(
- thresholdCheck: BehaviorThresholdCheck,
- remoteSupplier: Provider,
-) : AnrBehavior, MergedConfigBehavior(
- thresholdCheck = thresholdCheck,
- remoteSupplier = remoteSupplier
-) {
+ private val thresholdCheck: BehaviorThresholdCheck,
+ local: InstrumentedConfig,
+ remote: RemoteConfig?,
+) : AnrBehavior {
private companion object {
private const val DEFAULT_ANR_PCT_ENABLED = true
@@ -33,6 +29,9 @@ class AnrBehaviorImpl(
)
}
+ override val local = local.enabledFeatures
+ override val remote = remote?.anrConfig
+
override fun isAnrCaptureEnabled(): Boolean {
return thresholdCheck.isBehaviorEnabled(remote?.pctEnabled)
?: DEFAULT_ANR_PCT_ENABLED
@@ -64,7 +63,7 @@ class AnrBehaviorImpl(
override fun isUnityAnrCaptureEnabled(): Boolean {
return thresholdCheck.isBehaviorEnabled(remote?.pctNativeThreadAnrSamplingEnabled)
- ?: InstrumentedConfig.enabledFeatures.isUnityAnrCaptureEnabled()
+ ?: local.isUnityAnrCaptureEnabled()
}
override fun isNativeThreadAnrSamplingOffsetEnabled(): Boolean =
diff --git a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/behavior/AppExitInfoBehavior.kt b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/behavior/AppExitInfoBehavior.kt
index 59891abe99..4dd2ba5f6a 100644
--- a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/behavior/AppExitInfoBehavior.kt
+++ b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/behavior/AppExitInfoBehavior.kt
@@ -1,6 +1,9 @@
package io.embrace.android.embracesdk.internal.config.behavior
-interface AppExitInfoBehavior {
+import io.embrace.android.embracesdk.internal.config.instrumented.schema.EnabledFeatureConfig
+import io.embrace.android.embracesdk.internal.config.remote.AppExitInfoConfig
+
+interface AppExitInfoBehavior : ConfigBehavior {
fun getTraceMaxLimit(): Int
diff --git a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/behavior/AppExitInfoBehaviorImpl.kt b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/behavior/AppExitInfoBehaviorImpl.kt
index 9c11f0bc9c..b9d5cbca3c 100644
--- a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/behavior/AppExitInfoBehaviorImpl.kt
+++ b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/behavior/AppExitInfoBehaviorImpl.kt
@@ -1,21 +1,18 @@
package io.embrace.android.embracesdk.internal.config.behavior
-import io.embrace.android.embracesdk.internal.config.UnimplementedConfig
-import io.embrace.android.embracesdk.internal.config.instrumented.InstrumentedConfig
+import io.embrace.android.embracesdk.internal.config.instrumented.schema.InstrumentedConfig
import io.embrace.android.embracesdk.internal.config.remote.RemoteConfig
-import io.embrace.android.embracesdk.internal.utils.Provider
/**
* Provides the behavior that should be followed for select services that automatically
* capture data.
*/
class AppExitInfoBehaviorImpl(
- thresholdCheck: BehaviorThresholdCheck,
- remoteSupplier: Provider,
-) : AppExitInfoBehavior, MergedConfigBehavior(
- thresholdCheck = thresholdCheck,
- remoteSupplier = remoteSupplier
-) {
+ private val thresholdCheck: BehaviorThresholdCheck,
+ local: InstrumentedConfig,
+ remote: RemoteConfig?,
+) : AppExitInfoBehavior {
+
companion object {
/**
* Max size of bytes to allow capturing AppExitInfo ndk/anr traces
@@ -24,14 +21,17 @@ class AppExitInfoBehaviorImpl(
const val AEI_MAX_NUM_DEFAULT: Int = 0 // 0 means no limit
}
+ override val local = local.enabledFeatures
+ override val remote = remote?.appExitInfoConfig
+
override fun getTraceMaxLimit(): Int =
- remote?.appExitInfoConfig?.appExitInfoTracesLimit
+ remote?.appExitInfoTracesLimit
?: MAX_TRACE_SIZE_BYTES
override fun isAeiCaptureEnabled(): Boolean {
- return thresholdCheck.isBehaviorEnabled(remote?.appExitInfoConfig?.pctAeiCaptureEnabled)
- ?: InstrumentedConfig.enabledFeatures.isAeiCaptureEnabled()
+ return thresholdCheck.isBehaviorEnabled(remote?.pctAeiCaptureEnabled)
+ ?: local.isAeiCaptureEnabled()
}
- override fun appExitInfoMaxNum(): Int = remote?.appExitInfoConfig?.aeiMaxNum ?: AEI_MAX_NUM_DEFAULT
+ override fun appExitInfoMaxNum(): Int = remote?.aeiMaxNum ?: AEI_MAX_NUM_DEFAULT
}
diff --git a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/behavior/AutoDataCaptureBehavior.kt b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/behavior/AutoDataCaptureBehavior.kt
index a80d09b792..81641b26ff 100644
--- a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/behavior/AutoDataCaptureBehavior.kt
+++ b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/behavior/AutoDataCaptureBehavior.kt
@@ -1,6 +1,9 @@
package io.embrace.android.embracesdk.internal.config.behavior
-interface AutoDataCaptureBehavior {
+import io.embrace.android.embracesdk.internal.config.instrumented.schema.EnabledFeatureConfig
+import io.embrace.android.embracesdk.internal.config.remote.RemoteConfig
+
+interface AutoDataCaptureBehavior : ConfigBehavior {
/**
* Returns true if [io.embrace.android.embracesdk.MemoryService] should
diff --git a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/behavior/AutoDataCaptureBehaviorImpl.kt b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/behavior/AutoDataCaptureBehaviorImpl.kt
index e7e61eafa9..bd85048f23 100644
--- a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/behavior/AutoDataCaptureBehaviorImpl.kt
+++ b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/behavior/AutoDataCaptureBehaviorImpl.kt
@@ -1,21 +1,17 @@
package io.embrace.android.embracesdk.internal.config.behavior
-import io.embrace.android.embracesdk.internal.config.UnimplementedConfig
-import io.embrace.android.embracesdk.internal.config.instrumented.InstrumentedConfig
+import io.embrace.android.embracesdk.internal.config.instrumented.schema.InstrumentedConfig
import io.embrace.android.embracesdk.internal.config.remote.RemoteConfig
-import io.embrace.android.embracesdk.internal.utils.Provider
/**
* Provides the behavior that should be followed for select services that automatically
* capture data.
*/
class AutoDataCaptureBehaviorImpl(
- thresholdCheck: BehaviorThresholdCheck,
- remoteSupplier: Provider,
-) : AutoDataCaptureBehavior, MergedConfigBehavior(
- thresholdCheck = thresholdCheck,
- remoteSupplier = remoteSupplier
-) {
+ private val thresholdCheck: BehaviorThresholdCheck,
+ local: InstrumentedConfig,
+ override val remote: RemoteConfig?,
+) : AutoDataCaptureBehavior {
private companion object {
const val THERMAL_STATUS_ENABLED_DEFAULT = true
@@ -23,30 +19,30 @@ class AutoDataCaptureBehaviorImpl(
const val USE_OKHTTP_DEFAULT = true
}
- private val cfg = InstrumentedConfig.enabledFeatures
+ override val local = local.enabledFeatures
@Suppress("DEPRECATION")
- override fun isMemoryWarningCaptureEnabled(): Boolean = cfg.isMemoryWarningCaptureEnabled()
+ override fun isMemoryWarningCaptureEnabled(): Boolean = local.isMemoryWarningCaptureEnabled()
override fun isThermalStatusCaptureEnabled(): Boolean {
return thresholdCheck.isBehaviorEnabled(remote?.dataConfig?.pctThermalStatusEnabled)
?: THERMAL_STATUS_ENABLED_DEFAULT
}
- override fun isPowerSaveModeCaptureEnabled(): Boolean = cfg.isPowerSaveModeCaptureEnabled()
+ override fun isPowerSaveModeCaptureEnabled(): Boolean = local.isPowerSaveModeCaptureEnabled()
override fun isNetworkConnectivityCaptureEnabled(): Boolean =
- cfg.isNetworkConnectivityCaptureEnabled()
+ local.isNetworkConnectivityCaptureEnabled()
- override fun isAnrCaptureEnabled(): Boolean = cfg.isAnrCaptureEnabled()
- override fun isJvmCrashCaptureEnabled(): Boolean = cfg.isJvmCrashCaptureEnabled()
+ override fun isAnrCaptureEnabled(): Boolean = local.isAnrCaptureEnabled()
+ override fun isJvmCrashCaptureEnabled(): Boolean = local.isJvmCrashCaptureEnabled()
override fun isComposeClickCaptureEnabled(): Boolean =
- remote?.killSwitchConfig?.jetpackCompose ?: cfg.isComposeClickCaptureEnabled()
+ remote?.killSwitchConfig?.jetpackCompose ?: local.isComposeClickCaptureEnabled()
override fun is3rdPartySigHandlerDetectionEnabled(): Boolean =
- remote?.killSwitchConfig?.sigHandlerDetection ?: cfg.is3rdPartySigHandlerDetectionEnabled()
+ remote?.killSwitchConfig?.sigHandlerDetection ?: local.is3rdPartySigHandlerDetectionEnabled()
- override fun isNativeCrashCaptureEnabled(): Boolean = cfg.isNativeCrashCaptureEnabled()
- override fun isDiskUsageCaptureEnabled(): Boolean = cfg.isDiskUsageCaptureEnabled()
+ override fun isNativeCrashCaptureEnabled(): Boolean = local.isNativeCrashCaptureEnabled()
+ override fun isDiskUsageCaptureEnabled(): Boolean = local.isDiskUsageCaptureEnabled()
private val v2StorageImpl by lazy {
thresholdCheck.isBehaviorEnabled(remote?.killSwitchConfig?.v2StoragePct) ?: V2_STORAGE_ENABLED_DEFAULT
diff --git a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/behavior/BackgroundActivityBehavior.kt b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/behavior/BackgroundActivityBehavior.kt
index 6eef92ec52..9593815f3b 100644
--- a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/behavior/BackgroundActivityBehavior.kt
+++ b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/behavior/BackgroundActivityBehavior.kt
@@ -1,6 +1,9 @@
package io.embrace.android.embracesdk.internal.config.behavior
-interface BackgroundActivityBehavior {
+import io.embrace.android.embracesdk.internal.config.instrumented.schema.EnabledFeatureConfig
+import io.embrace.android.embracesdk.internal.config.remote.BackgroundActivityRemoteConfig
+
+interface BackgroundActivityBehavior : ConfigBehavior {
/**
* Whether the feature is enabled or not.
diff --git a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/behavior/BackgroundActivityBehaviorImpl.kt b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/behavior/BackgroundActivityBehaviorImpl.kt
index 14ab1ac00b..12e488b02e 100644
--- a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/behavior/BackgroundActivityBehaviorImpl.kt
+++ b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/behavior/BackgroundActivityBehaviorImpl.kt
@@ -1,25 +1,25 @@
package io.embrace.android.embracesdk.internal.config.behavior
-import io.embrace.android.embracesdk.internal.config.UnimplementedConfig
-import io.embrace.android.embracesdk.internal.config.instrumented.InstrumentedConfig
+import io.embrace.android.embracesdk.internal.config.instrumented.schema.EnabledFeatureConfig
+import io.embrace.android.embracesdk.internal.config.instrumented.schema.InstrumentedConfig
import io.embrace.android.embracesdk.internal.config.remote.BackgroundActivityRemoteConfig
-import io.embrace.android.embracesdk.internal.utils.Provider
+import io.embrace.android.embracesdk.internal.config.remote.RemoteConfig
/**
* Provides the behavior that the Background Activity feature should follow.
*/
class BackgroundActivityBehaviorImpl(
- thresholdCheck: BehaviorThresholdCheck,
- remoteSupplier: Provider,
-) : BackgroundActivityBehavior,
- MergedConfigBehavior(
- thresholdCheck = thresholdCheck,
- remoteSupplier = remoteSupplier
- ) {
+ private val thresholdCheck: BehaviorThresholdCheck,
+ local: InstrumentedConfig,
+ remote: RemoteConfig?,
+) : BackgroundActivityBehavior {
+
+ override val local: EnabledFeatureConfig = local.enabledFeatures
+ override val remote: BackgroundActivityRemoteConfig? = remote?.backgroundActivityConfig
override fun isBackgroundActivityCaptureEnabled(): Boolean {
return remote?.threshold?.let(thresholdCheck::isBehaviorEnabled)
- ?: InstrumentedConfig.enabledFeatures.isBackgroundActivityCaptureEnabled()
+ ?: local.isBackgroundActivityCaptureEnabled()
}
override fun getManualBackgroundActivityLimit(): Int = 100
diff --git a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/behavior/BreadcrumbBehavior.kt b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/behavior/BreadcrumbBehavior.kt
index 275313f5d6..2d28ea5845 100644
--- a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/behavior/BreadcrumbBehavior.kt
+++ b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/behavior/BreadcrumbBehavior.kt
@@ -1,6 +1,9 @@
package io.embrace.android.embracesdk.internal.config.behavior
-interface BreadcrumbBehavior {
+import io.embrace.android.embracesdk.internal.config.instrumented.schema.EnabledFeatureConfig
+import io.embrace.android.embracesdk.internal.config.remote.RemoteConfig
+
+interface BreadcrumbBehavior : ConfigBehavior {
fun getCustomBreadcrumbLimit(): Int
fun getFragmentBreadcrumbLimit(): Int
diff --git a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/behavior/BreadcrumbBehaviorImpl.kt b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/behavior/BreadcrumbBehaviorImpl.kt
index 8a0e6fe5b4..0e9ae8217c 100644
--- a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/behavior/BreadcrumbBehaviorImpl.kt
+++ b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/behavior/BreadcrumbBehaviorImpl.kt
@@ -1,21 +1,17 @@
package io.embrace.android.embracesdk.internal.config.behavior
-import io.embrace.android.embracesdk.internal.config.UnimplementedConfig
-import io.embrace.android.embracesdk.internal.config.instrumented.InstrumentedConfig
+import io.embrace.android.embracesdk.internal.config.instrumented.schema.EnabledFeatureConfig
+import io.embrace.android.embracesdk.internal.config.instrumented.schema.InstrumentedConfig
import io.embrace.android.embracesdk.internal.config.remote.RemoteConfig
-import io.embrace.android.embracesdk.internal.utils.Provider
/**
* Provides the behavior that should be followed for select services that automatically
* capture data.
*/
class BreadcrumbBehaviorImpl(
- thresholdCheck: BehaviorThresholdCheck,
- remoteSupplier: Provider,
-) : BreadcrumbBehavior, MergedConfigBehavior(
- thresholdCheck = thresholdCheck,
- remoteSupplier = remoteSupplier
-) {
+ local: InstrumentedConfig,
+ override val remote: RemoteConfig?,
+) : BreadcrumbBehavior {
private companion object {
@@ -25,7 +21,7 @@ class BreadcrumbBehaviorImpl(
const val DEFAULT_BREADCRUMB_LIMIT = 100
}
- private val cfg = InstrumentedConfig.enabledFeatures
+ override val local: EnabledFeatureConfig = local.enabledFeatures
override fun getCustomBreadcrumbLimit(): Int =
remote?.uiConfig?.breadcrumbs ?: DEFAULT_BREADCRUMB_LIMIT
@@ -38,16 +34,16 @@ class BreadcrumbBehaviorImpl(
remote?.uiConfig?.webViews ?: DEFAULT_BREADCRUMB_LIMIT
override fun isViewClickCoordinateCaptureEnabled(): Boolean =
- cfg.isViewClickCoordinateCaptureEnabled()
+ local.isViewClickCoordinateCaptureEnabled()
override fun isActivityBreadcrumbCaptureEnabled(): Boolean =
- cfg.isActivityBreadcrumbCaptureEnabled()
+ local.isActivityBreadcrumbCaptureEnabled()
override fun isWebViewBreadcrumbCaptureEnabled(): Boolean =
- cfg.isWebViewBreadcrumbCaptureEnabled()
+ local.isWebViewBreadcrumbCaptureEnabled()
override fun isWebViewBreadcrumbQueryParamCaptureEnabled(): Boolean =
- cfg.isWebViewBreadcrumbQueryParamCaptureEnabled()
+ local.isWebViewBreadcrumbQueryParamCaptureEnabled()
- override fun isFcmPiiDataCaptureEnabled(): Boolean = cfg.isFcmPiiDataCaptureEnabled()
+ override fun isFcmPiiDataCaptureEnabled(): Boolean = local.isFcmPiiDataCaptureEnabled()
}
diff --git a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/behavior/ConfigBehavior.kt b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/behavior/ConfigBehavior.kt
new file mode 100644
index 0000000000..12272e1ebe
--- /dev/null
+++ b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/behavior/ConfigBehavior.kt
@@ -0,0 +1,17 @@
+package io.embrace.android.embracesdk.internal.config.behavior
+
+/**
+ * Determines the SDK's behavior at runtime. These values are immutable for the process lifetime.
+ */
+interface ConfigBehavior {
+
+ /**
+ * The local config.
+ */
+ val local: L
+
+ /**
+ * The remote config.
+ */
+ val remote: R?
+}
diff --git a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/behavior/DataCaptureEventBehavior.kt b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/behavior/DataCaptureEventBehavior.kt
index 1bd75beb70..0baa98ef53 100644
--- a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/behavior/DataCaptureEventBehavior.kt
+++ b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/behavior/DataCaptureEventBehavior.kt
@@ -1,6 +1,9 @@
package io.embrace.android.embracesdk.internal.config.behavior
-interface DataCaptureEventBehavior {
+import io.embrace.android.embracesdk.internal.config.UnimplementedConfig
+import io.embrace.android.embracesdk.internal.config.remote.RemoteConfig
+
+interface DataCaptureEventBehavior : ConfigBehavior {
fun isInternalExceptionCaptureEnabled(): Boolean
fun isEventEnabled(eventName: String): Boolean
fun isLogMessageEnabled(logMessage: String): Boolean
diff --git a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/behavior/DataCaptureEventBehaviorImpl.kt b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/behavior/DataCaptureEventBehaviorImpl.kt
index 975db6ae24..9ec6135610 100644
--- a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/behavior/DataCaptureEventBehaviorImpl.kt
+++ b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/behavior/DataCaptureEventBehaviorImpl.kt
@@ -3,20 +3,17 @@ package io.embrace.android.embracesdk.internal.config.behavior
import io.embrace.android.embracesdk.internal.PatternCache
import io.embrace.android.embracesdk.internal.config.UnimplementedConfig
import io.embrace.android.embracesdk.internal.config.remote.RemoteConfig
-import io.embrace.android.embracesdk.internal.utils.Provider
class DataCaptureEventBehaviorImpl(
- thresholdCheck: BehaviorThresholdCheck,
- remoteSupplier: Provider = { null },
-) : DataCaptureEventBehavior, MergedConfigBehavior(
- thresholdCheck = thresholdCheck,
- remoteSupplier = remoteSupplier
-) {
+ override val remote: RemoteConfig?,
+) : DataCaptureEventBehavior {
private companion object {
private const val DEFAULT_INTERNAL_EXCEPTION_CAPTURE = true
}
+ override val local: UnimplementedConfig = null
+
private val patternCache = PatternCache()
override fun isInternalExceptionCaptureEnabled(): Boolean =
diff --git a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/behavior/LogMessageBehavior.kt b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/behavior/LogMessageBehavior.kt
index 616fba870e..8c3286880d 100644
--- a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/behavior/LogMessageBehavior.kt
+++ b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/behavior/LogMessageBehavior.kt
@@ -1,6 +1,9 @@
package io.embrace.android.embracesdk.internal.config.behavior
-interface LogMessageBehavior {
+import io.embrace.android.embracesdk.internal.config.UnimplementedConfig
+import io.embrace.android.embracesdk.internal.config.remote.LogRemoteConfig
+
+interface LogMessageBehavior : ConfigBehavior {
fun getLogMessageMaximumAllowedLength(): Int
fun getInfoLogLimit(): Int
fun getWarnLogLimit(): Int
diff --git a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/behavior/LogMessageBehaviorImpl.kt b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/behavior/LogMessageBehaviorImpl.kt
index a6a35771a1..57865b27c2 100644
--- a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/behavior/LogMessageBehaviorImpl.kt
+++ b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/behavior/LogMessageBehaviorImpl.kt
@@ -2,18 +2,14 @@ package io.embrace.android.embracesdk.internal.config.behavior
import io.embrace.android.embracesdk.internal.config.UnimplementedConfig
import io.embrace.android.embracesdk.internal.config.remote.LogRemoteConfig
-import io.embrace.android.embracesdk.internal.utils.Provider
+import io.embrace.android.embracesdk.internal.config.remote.RemoteConfig
/**
* Provides the behavior that should be followed for remote log message functionality.
*/
class LogMessageBehaviorImpl(
- thresholdCheck: BehaviorThresholdCheck,
- remoteSupplier: Provider,
-) : LogMessageBehavior, MergedConfigBehavior(
- thresholdCheck = thresholdCheck,
- remoteSupplier = remoteSupplier
-) {
+ remote: RemoteConfig?,
+) : LogMessageBehavior {
private companion object {
private const val DEFAULT_LOG_INFO_LIMIT = 100
@@ -21,6 +17,9 @@ class LogMessageBehaviorImpl(
private const val DEFAULT_LOG_ERROR_LIMIT = 250
}
+ override val remote: LogRemoteConfig? = remote?.logConfig
+ override val local: UnimplementedConfig = null
+
override fun getLogMessageMaximumAllowedLength(): Int {
return remote?.logMessageMaximumAllowedLength ?: LOG_MESSAGE_MAXIMUM_ALLOWED_LENGTH
}
diff --git a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/behavior/MergedConfigBehavior.kt b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/behavior/MergedConfigBehavior.kt
deleted file mode 100644
index 82cec4268c..0000000000
--- a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/behavior/MergedConfigBehavior.kt
+++ /dev/null
@@ -1,50 +0,0 @@
-package io.embrace.android.embracesdk.internal.config.behavior
-
-import io.embrace.android.embracesdk.internal.utils.Provider
-
-/**
- * Merges multiple sources of config and tells the SDK how its functionality should behave. This
- * means the caller doesn't need to worry about whether the remote config has been fetched or its
- * precedence rules - it just gets told whether it should enable something or not.
- *
- * There are three sources of config: remote (from the config endpoint); local (from the
- * embrace-config.json); and default (defined in subclasses of this type).
- *
- * Config is typically evaluated in the following precedence: Remote > Local > Default. Remote/local
- * configs might not exist for every single field, as it doesn't always make sense for every value
- * to be configurable by end-users. However, there should always be a default value.
- */
-open class MergedConfigBehavior(
-
- /**
- * Checks whether percent-based thresholds should be enabled or not. We should always return
- * booleans about whether functionality is enabled - and should never expose percentages etc
- * to the caller.
- */
- protected val thresholdCheck: BehaviorThresholdCheck,
-
- /**
- * Supplier for local config, from the embrace-config.json file.
- */
- private val localSupplier: Provider = { null },
-
- /**
- * Supplier for remote config, from the config endpoint.
- */
- private val remoteSupplier: Provider = { null },
-) {
-
- /**
- * The local config. This property always returns the most up-to-date value, or null if
- * no local config is available.
- */
- protected val local: L?
- get() = localSupplier()
-
- /**
- * The remote config. This property always returns the most up-to-date value, or null if
- * no remote config is available.
- */
- protected val remote: R?
- get() = remoteSupplier()
-}
diff --git a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/behavior/NetworkBehavior.kt b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/behavior/NetworkBehavior.kt
index 93f1619f48..cecd77f8ba 100644
--- a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/behavior/NetworkBehavior.kt
+++ b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/behavior/NetworkBehavior.kt
@@ -1,8 +1,10 @@
package io.embrace.android.embracesdk.internal.config.behavior
+import io.embrace.android.embracesdk.internal.config.instrumented.schema.InstrumentedConfig
import io.embrace.android.embracesdk.internal.config.remote.NetworkCaptureRuleRemoteConfig
+import io.embrace.android.embracesdk.internal.config.remote.RemoteConfig
-interface NetworkBehavior {
+interface NetworkBehavior : ConfigBehavior {
/**
* Control whether request size for native Android requests is captured.
diff --git a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/behavior/NetworkBehaviorImpl.kt b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/behavior/NetworkBehaviorImpl.kt
index 079b64adc7..6ff586806b 100644
--- a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/behavior/NetworkBehaviorImpl.kt
+++ b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/behavior/NetworkBehaviorImpl.kt
@@ -1,10 +1,8 @@
package io.embrace.android.embracesdk.internal.config.behavior
-import io.embrace.android.embracesdk.internal.config.UnimplementedConfig
-import io.embrace.android.embracesdk.internal.config.instrumented.InstrumentedConfig
+import io.embrace.android.embracesdk.internal.config.instrumented.schema.InstrumentedConfig
import io.embrace.android.embracesdk.internal.config.remote.NetworkCaptureRuleRemoteConfig
import io.embrace.android.embracesdk.internal.config.remote.RemoteConfig
-import io.embrace.android.embracesdk.internal.utils.Provider
import java.util.regex.Pattern
import kotlin.math.min
@@ -12,13 +10,10 @@ import kotlin.math.min
* Provides the behavior that functionality relating to network call capture should follow.
*/
class NetworkBehaviorImpl(
- thresholdCheck: BehaviorThresholdCheck,
- remoteSupplier: Provider,
+ override val local: InstrumentedConfig,
+ override val remote: RemoteConfig?,
private val disabledUrlPatterns: List? = null,
-) : NetworkBehavior, MergedConfigBehavior(
- thresholdCheck = thresholdCheck,
- remoteSupplier = remoteSupplier
-) {
+) : NetworkBehavior {
companion object {
@@ -34,13 +29,13 @@ class NetworkBehaviorImpl(
)
}
- private val cfg = InstrumentedConfig.networkCapture
+ private val cfg = local.networkCapture
override fun isRequestContentLengthCaptureEnabled(): Boolean =
- InstrumentedConfig.enabledFeatures.isRequestContentLengthCaptureEnabled()
+ local.enabledFeatures.isRequestContentLengthCaptureEnabled()
override fun isHttpUrlConnectionCaptureEnabled(): Boolean =
- InstrumentedConfig.enabledFeatures.isHttpUrlConnectionCaptureEnabled()
+ local.enabledFeatures.isHttpUrlConnectionCaptureEnabled()
override fun getLimitsByDomain(): Map {
val limits = remote?.networkConfig?.domainLimits ?: cfg.getLimitsByDomain()
diff --git a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/behavior/NetworkSpanForwardingBehavior.kt b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/behavior/NetworkSpanForwardingBehavior.kt
index 9eca2f524d..cf27edb0af 100644
--- a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/behavior/NetworkSpanForwardingBehavior.kt
+++ b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/behavior/NetworkSpanForwardingBehavior.kt
@@ -1,5 +1,8 @@
package io.embrace.android.embracesdk.internal.config.behavior
-interface NetworkSpanForwardingBehavior {
+import io.embrace.android.embracesdk.internal.config.instrumented.schema.EnabledFeatureConfig
+import io.embrace.android.embracesdk.internal.config.remote.NetworkSpanForwardingRemoteConfig
+
+interface NetworkSpanForwardingBehavior : ConfigBehavior {
fun isNetworkSpanForwardingEnabled(): Boolean
}
diff --git a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/behavior/NetworkSpanForwardingBehaviorImpl.kt b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/behavior/NetworkSpanForwardingBehaviorImpl.kt
index a5a3cf8a7c..e9dce91e95 100644
--- a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/behavior/NetworkSpanForwardingBehaviorImpl.kt
+++ b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/behavior/NetworkSpanForwardingBehaviorImpl.kt
@@ -1,17 +1,16 @@
package io.embrace.android.embracesdk.internal.config.behavior
-import io.embrace.android.embracesdk.internal.config.UnimplementedConfig
-import io.embrace.android.embracesdk.internal.config.instrumented.InstrumentedConfig
+import io.embrace.android.embracesdk.internal.config.instrumented.schema.EnabledFeatureConfig
+import io.embrace.android.embracesdk.internal.config.instrumented.schema.InstrumentedConfig
import io.embrace.android.embracesdk.internal.config.remote.NetworkSpanForwardingRemoteConfig
-import io.embrace.android.embracesdk.internal.utils.Provider
+import io.embrace.android.embracesdk.internal.config.remote.RemoteConfig
class NetworkSpanForwardingBehaviorImpl(
- thresholdCheck: BehaviorThresholdCheck,
- remoteSupplier: Provider,
-) : NetworkSpanForwardingBehavior, MergedConfigBehavior(
- thresholdCheck = thresholdCheck,
- remoteSupplier = remoteSupplier
-) {
+ private val thresholdCheck: BehaviorThresholdCheck,
+ local: InstrumentedConfig,
+ remote: RemoteConfig?,
+) : NetworkSpanForwardingBehavior {
+
companion object {
/**
* Header name for the W3C traceparent
@@ -19,8 +18,11 @@ class NetworkSpanForwardingBehaviorImpl(
const val TRACEPARENT_HEADER_NAME: String = "traceparent"
}
+ override val local: EnabledFeatureConfig = local.enabledFeatures
+ override val remote: NetworkSpanForwardingRemoteConfig? = remote?.networkSpanForwardingRemoteConfig
+
override fun isNetworkSpanForwardingEnabled(): Boolean {
return remote?.pctEnabled?.let { thresholdCheck.isBehaviorEnabled(it) }
- ?: InstrumentedConfig.enabledFeatures.isNetworkSpanForwardingEnabled()
+ ?: local.isNetworkSpanForwardingEnabled()
}
}
diff --git a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/behavior/SdkEndpointBehavior.kt b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/behavior/SdkEndpointBehavior.kt
deleted file mode 100644
index cf00721f0b..0000000000
--- a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/behavior/SdkEndpointBehavior.kt
+++ /dev/null
@@ -1,14 +0,0 @@
-package io.embrace.android.embracesdk.internal.config.behavior
-
-interface SdkEndpointBehavior {
-
- /**
- * Data base URL.
- */
- fun getData(appId: String?): String
-
- /**
- * Config base URL.
- */
- fun getConfig(appId: String?): String
-}
diff --git a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/behavior/SdkEndpointBehaviorImpl.kt b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/behavior/SdkEndpointBehaviorImpl.kt
deleted file mode 100644
index c908301adf..0000000000
--- a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/behavior/SdkEndpointBehaviorImpl.kt
+++ /dev/null
@@ -1,33 +0,0 @@
-package io.embrace.android.embracesdk.internal.config.behavior
-
-import io.embrace.android.embracesdk.internal.config.UnimplementedConfig
-import io.embrace.android.embracesdk.internal.config.instrumented.InstrumentedConfig
-
-/**
- * Provides the behavior that the Background Activity feature should follow.
- */
-class SdkEndpointBehaviorImpl(
- thresholdCheck: BehaviorThresholdCheck,
-) : SdkEndpointBehavior, MergedConfigBehavior(
- thresholdCheck = thresholdCheck
-) {
-
- companion object {
- const val CONFIG_DEFAULT: String = "config.emb-api.com"
- const val DATA_DEFAULT: String = "data.emb-api.com"
- }
-
- override fun getData(appId: String?): String {
- if (appId == null) {
- return ""
- }
- return InstrumentedConfig.baseUrls.getData() ?: "https://a-$appId.$DATA_DEFAULT"
- }
-
- override fun getConfig(appId: String?): String {
- if (appId == null) {
- return ""
- }
- return InstrumentedConfig.baseUrls.getConfig() ?: "https://a-$appId.$CONFIG_DEFAULT"
- }
-}
diff --git a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/behavior/SdkModeBehavior.kt b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/behavior/SdkModeBehavior.kt
index e0dcd39c8c..402f546fef 100644
--- a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/behavior/SdkModeBehavior.kt
+++ b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/behavior/SdkModeBehavior.kt
@@ -1,6 +1,9 @@
package io.embrace.android.embracesdk.internal.config.behavior
-interface SdkModeBehavior {
+import io.embrace.android.embracesdk.internal.config.UnimplementedConfig
+import io.embrace.android.embracesdk.internal.config.remote.RemoteConfig
+
+interface SdkModeBehavior : ConfigBehavior {
/**
* Given a Config instance, computes if the SDK is enabled based on the threshold and the offset.
diff --git a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/behavior/SdkModeBehaviorImpl.kt b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/behavior/SdkModeBehaviorImpl.kt
index 7821b8a1b5..fa6edb95da 100644
--- a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/behavior/SdkModeBehaviorImpl.kt
+++ b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/behavior/SdkModeBehaviorImpl.kt
@@ -2,7 +2,6 @@ package io.embrace.android.embracesdk.internal.config.behavior
import io.embrace.android.embracesdk.internal.config.UnimplementedConfig
import io.embrace.android.embracesdk.internal.config.remote.RemoteConfig
-import io.embrace.android.embracesdk.internal.utils.Provider
import kotlin.math.max
import kotlin.math.min
@@ -10,12 +9,9 @@ import kotlin.math.min
* Provides whether the SDK should enable certain 'behavior' modes, such as 'integration mode'
*/
class SdkModeBehaviorImpl(
- thresholdCheck: BehaviorThresholdCheck,
- remoteSupplier: Provider,
-) : SdkModeBehavior, MergedConfigBehavior(
- thresholdCheck = thresholdCheck,
- remoteSupplier = remoteSupplier
-) {
+ private val thresholdCheck: BehaviorThresholdCheck,
+ override val remote: RemoteConfig?,
+) : SdkModeBehavior {
private companion object {
@@ -30,6 +26,8 @@ class SdkModeBehaviorImpl(
private const val DEFAULT_OFFSET = 0
}
+ override val local: UnimplementedConfig = null
+
/**
* The % of devices that should be enabled.
*/
diff --git a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/behavior/SensitiveKeysBehavior.kt b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/behavior/SensitiveKeysBehavior.kt
index 17384d73e2..9aa968c074 100644
--- a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/behavior/SensitiveKeysBehavior.kt
+++ b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/behavior/SensitiveKeysBehavior.kt
@@ -1,6 +1,9 @@
package io.embrace.android.embracesdk.internal.config.behavior
-fun interface SensitiveKeysBehavior {
+import io.embrace.android.embracesdk.internal.config.UnimplementedConfig
+import io.embrace.android.embracesdk.internal.config.instrumented.schema.RedactionConfig
+
+interface SensitiveKeysBehavior : ConfigBehavior {
/**
* Checks if the given key is sensitive.
diff --git a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/behavior/SensitiveKeysBehaviorImpl.kt b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/behavior/SensitiveKeysBehaviorImpl.kt
index 46e417b4f5..50240078f3 100644
--- a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/behavior/SensitiveKeysBehaviorImpl.kt
+++ b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/behavior/SensitiveKeysBehaviorImpl.kt
@@ -1,16 +1,22 @@
package io.embrace.android.embracesdk.internal.config.behavior
-import io.embrace.android.embracesdk.internal.config.instrumented.InstrumentedConfig
+import io.embrace.android.embracesdk.internal.config.UnimplementedConfig
+import io.embrace.android.embracesdk.internal.config.instrumented.schema.InstrumentedConfig
+import io.embrace.android.embracesdk.internal.config.instrumented.schema.RedactionConfig
private const val SENSITIVE_KEY_MAX_LENGTH = 128
private const val SENSITIVE_KEYS_LIST_MAX_SIZE = 10000
const val REDACTED_LABEL: String = ""
-class SensitiveKeysBehaviorImpl(denyList: List? = null) : SensitiveKeysBehavior {
+class SensitiveKeysBehaviorImpl(
+ local: InstrumentedConfig,
+) : SensitiveKeysBehavior {
- private val denyList =
- (denyList ?: InstrumentedConfig.redaction.getSensitiveKeysDenylist())?.take(SENSITIVE_KEYS_LIST_MAX_SIZE)
+ override val local: RedactionConfig = local.redaction
+ override val remote: UnimplementedConfig = null
+
+ private val denyList = local.redaction.getSensitiveKeysDenylist()?.take(SENSITIVE_KEYS_LIST_MAX_SIZE)
override fun isSensitiveKey(key: String): Boolean {
return denyList?.any { it.take(SENSITIVE_KEY_MAX_LENGTH) == key } ?: false
diff --git a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/behavior/SessionBehavior.kt b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/behavior/SessionBehavior.kt
index cdb2f81f62..3ef59e5479 100644
--- a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/behavior/SessionBehavior.kt
+++ b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/behavior/SessionBehavior.kt
@@ -1,6 +1,9 @@
package io.embrace.android.embracesdk.internal.config.behavior
-interface SessionBehavior {
+import io.embrace.android.embracesdk.internal.config.instrumented.schema.SessionConfig
+import io.embrace.android.embracesdk.internal.config.remote.RemoteConfig
+
+interface SessionBehavior : ConfigBehavior {
/**
* The whitelist of events (crashes, errors) that should send a full session payload even
diff --git a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/behavior/SessionBehaviorImpl.kt b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/behavior/SessionBehaviorImpl.kt
index 6dd88269ea..b7c44824ea 100644
--- a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/behavior/SessionBehaviorImpl.kt
+++ b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/behavior/SessionBehaviorImpl.kt
@@ -1,34 +1,32 @@
package io.embrace.android.embracesdk.internal.config.behavior
-import io.embrace.android.embracesdk.internal.config.UnimplementedConfig
-import io.embrace.android.embracesdk.internal.config.instrumented.InstrumentedConfig
+import io.embrace.android.embracesdk.internal.config.instrumented.schema.InstrumentedConfig
+import io.embrace.android.embracesdk.internal.config.instrumented.schema.SessionConfig
import io.embrace.android.embracesdk.internal.config.remote.RemoteConfig
import io.embrace.android.embracesdk.internal.gating.SessionGatingKeys
-import io.embrace.android.embracesdk.internal.utils.Provider
import java.util.Locale
/**
* Provides the behavior that functionality relating to sessions should follow.
*/
class SessionBehaviorImpl(
- thresholdCheck: BehaviorThresholdCheck,
- remoteSupplier: Provider,
-) : SessionBehavior, MergedConfigBehavior(
- thresholdCheck = thresholdCheck,
- remoteSupplier = remoteSupplier
-) {
+ local: InstrumentedConfig,
+ override val remote: RemoteConfig?,
+) : SessionBehavior {
companion object {
const val SESSION_PROPERTY_LIMIT: Int = 10
}
+ override val local: SessionConfig = local.session
+
override fun getFullSessionEvents(): Set {
- val strings = remote?.sessionConfig?.fullSessionEvents ?: InstrumentedConfig.session.getFullSessionEvents()
+ val strings = remote?.sessionConfig?.fullSessionEvents ?: local.getFullSessionEvents()
return strings.map { it.lowercase(Locale.US) }.toSet()
}
override fun getSessionComponents(): Set? =
- (remote?.sessionConfig?.sessionComponents ?: InstrumentedConfig.session.getSessionComponents())?.toSet()
+ (remote?.sessionConfig?.sessionComponents ?: local.getSessionComponents())?.toSet()
override fun isGatingFeatureEnabled(): Boolean = getSessionComponents() != null
diff --git a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/behavior/WebViewVitalsBehavior.kt b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/behavior/WebViewVitalsBehavior.kt
index 7950e3b9e3..3222362af8 100644
--- a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/behavior/WebViewVitalsBehavior.kt
+++ b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/behavior/WebViewVitalsBehavior.kt
@@ -1,6 +1,9 @@
package io.embrace.android.embracesdk.internal.config.behavior
-interface WebViewVitalsBehavior {
+import io.embrace.android.embracesdk.internal.config.UnimplementedConfig
+import io.embrace.android.embracesdk.internal.config.remote.RemoteConfig
+
+interface WebViewVitalsBehavior : ConfigBehavior {
fun getMaxWebViewVitals(): Int
fun isWebViewVitalsEnabled(): Boolean
}
diff --git a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/behavior/WebViewVitalsBehaviorImpl.kt b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/behavior/WebViewVitalsBehaviorImpl.kt
index 2131bf498e..d3db9519af 100644
--- a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/behavior/WebViewVitalsBehaviorImpl.kt
+++ b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/behavior/WebViewVitalsBehaviorImpl.kt
@@ -2,15 +2,11 @@ package io.embrace.android.embracesdk.internal.config.behavior
import io.embrace.android.embracesdk.internal.config.UnimplementedConfig
import io.embrace.android.embracesdk.internal.config.remote.RemoteConfig
-import io.embrace.android.embracesdk.internal.utils.Provider
class WebViewVitalsBehaviorImpl(
- thresholdCheck: BehaviorThresholdCheck,
- remoteSupplier: Provider,
-) : WebViewVitalsBehavior, MergedConfigBehavior(
- thresholdCheck = thresholdCheck,
- remoteSupplier = remoteSupplier
-) {
+ private val thresholdCheck: BehaviorThresholdCheck,
+ override val remote: RemoteConfig?,
+) : WebViewVitalsBehavior {
private companion object {
/**
@@ -24,6 +20,8 @@ class WebViewVitalsBehaviorImpl(
private const val DEFAULT_MAX_VITALS = 300
}
+ override val local: UnimplementedConfig = null
+
private fun getWebVitalsPct(): Float = remote?.webViewVitals?.pctEnabled ?: DEFAULT_WEB_VITALS_PCT
override fun getMaxWebViewVitals(): Int = remote?.webViewVitals?.maxVitals ?: DEFAULT_MAX_VITALS
diff --git a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/source/CombinedRemoteConfigSource.kt b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/source/CombinedRemoteConfigSource.kt
new file mode 100644
index 0000000000..ccd23dcb82
--- /dev/null
+++ b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/source/CombinedRemoteConfigSource.kt
@@ -0,0 +1,46 @@
+package io.embrace.android.embracesdk.internal.config.source
+
+import io.embrace.android.embracesdk.internal.Systrace
+import io.embrace.android.embracesdk.internal.config.remote.RemoteConfig
+import io.embrace.android.embracesdk.internal.config.store.RemoteConfigStore
+import io.embrace.android.embracesdk.internal.worker.BackgroundWorker
+import java.util.concurrent.TimeUnit
+
+class CombinedRemoteConfigSource(
+ private val store: RemoteConfigStore,
+ httpSource: Lazy,
+ private val worker: BackgroundWorker,
+ private val intervalMs: Long = 60 * 60 * 1000
+) {
+
+ private val httpSource: RemoteConfigSource by httpSource
+
+ // the remote config that is used for the lifetime of the process.
+ private val response by lazy {
+ Systrace.traceSynchronous("load-config-from-store") {
+ store.loadResponse()
+ }
+ }
+
+ fun getConfig(): RemoteConfig? = response?.cfg
+
+ fun scheduleConfigRequests() {
+ Systrace.traceSynchronous("set-initial-etag") {
+ response?.etag?.let(httpSource::setInitialEtag)
+ }
+ Systrace.traceSynchronous("schedule-http-request") {
+ worker.scheduleWithFixedDelay(
+ ::attemptConfigRequest,
+ 0,
+ intervalMs,
+ TimeUnit.MILLISECONDS
+ )
+ }
+ }
+
+ private fun attemptConfigRequest() {
+ httpSource.getConfig()?.let {
+ store.saveResponse(it)
+ }
+ }
+}
diff --git a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/source/ConfigHttpResponse.kt b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/source/ConfigHttpResponse.kt
new file mode 100644
index 0000000000..a542c5774e
--- /dev/null
+++ b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/source/ConfigHttpResponse.kt
@@ -0,0 +1,8 @@
+package io.embrace.android.embracesdk.internal.config.source
+
+import io.embrace.android.embracesdk.internal.config.remote.RemoteConfig
+
+data class ConfigHttpResponse(
+ val cfg: RemoteConfig?,
+ val etag: String?,
+)
diff --git a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/source/OkHttpRemoteConfigSource.kt b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/source/OkHttpRemoteConfigSource.kt
new file mode 100644
index 0000000000..763fb68b53
--- /dev/null
+++ b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/source/OkHttpRemoteConfigSource.kt
@@ -0,0 +1,83 @@
+package io.embrace.android.embracesdk.internal.config.source
+
+import io.embrace.android.embracesdk.core.BuildConfig
+import io.embrace.android.embracesdk.internal.comms.api.ApiRequest
+import io.embrace.android.embracesdk.internal.comms.api.ApiRequestUrl
+import io.embrace.android.embracesdk.internal.comms.api.ApiUrlBuilder
+import io.embrace.android.embracesdk.internal.comms.api.Endpoint
+import io.embrace.android.embracesdk.internal.comms.api.getHeaders
+import io.embrace.android.embracesdk.internal.config.remote.RemoteConfig
+import io.embrace.android.embracesdk.internal.serialization.PlatformSerializer
+import io.embrace.android.embracesdk.network.http.HttpMethod
+import okhttp3.OkHttpClient
+import okhttp3.Request
+import okhttp3.Response
+import okio.GzipSource
+import okio.buffer
+import java.io.IOException
+
+internal class OkHttpRemoteConfigSource(
+ private val okhttpClient: OkHttpClient,
+ private val apiUrlBuilder: ApiUrlBuilder,
+ private val serializer: PlatformSerializer,
+) : RemoteConfigSource {
+
+ override fun getConfig(): ConfigHttpResponse? = try {
+ fetchConfigImpl()
+ } catch (exc: IOException) {
+ null
+ }
+
+ override fun setInitialEtag(etag: String) {
+ this.etag = etag
+ }
+
+ private var etag: String? = null
+
+ private fun fetchConfigImpl(): ConfigHttpResponse? {
+ val request = prepareRequest()
+ val call = okhttpClient.newCall(request)
+ val response = call.execute()
+ return processResponse(response)
+ }
+
+ private fun prepareRequest(): Request {
+ val url = apiUrlBuilder.resolveUrl(Endpoint.CONFIG)
+ val headers = prepareConfigRequest(url).getHeaders()
+ val builder = Request.Builder().url(url)
+
+ etag?.let {
+ builder.header("If-None-Match", it)
+ }
+ headers.forEach { entry ->
+ builder.header(entry.key, entry.value)
+ }
+ val request = builder.build()
+ return request
+ }
+
+ private fun processResponse(response: Response): ConfigHttpResponse? {
+ response.header("etag")?.let {
+ this.etag = it
+ }
+ if (!response.isSuccessful) {
+ return null
+ }
+ val cfg = response.body?.source()?.use { src ->
+ val gzipSource = GzipSource(src)
+ gzipSource.buffer().inputStream().use {
+ serializer.fromJson(it, RemoteConfig::class.java)
+ }
+ }
+ return ConfigHttpResponse(cfg, etag)
+ }
+
+ private fun prepareConfigRequest(url: String) = ApiRequest(
+ userAgent = "Embrace/a/" + BuildConfig.VERSION_NAME,
+ url = ApiRequestUrl(url),
+ httpMethod = HttpMethod.GET,
+ acceptEncoding = "gzip",
+ appId = apiUrlBuilder.appId,
+ deviceId = apiUrlBuilder.deviceId,
+ )
+}
diff --git a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/source/RemoteConfigSource.kt b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/source/RemoteConfigSource.kt
new file mode 100644
index 0000000000..7655fff992
--- /dev/null
+++ b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/source/RemoteConfigSource.kt
@@ -0,0 +1,14 @@
+package io.embrace.android.embracesdk.internal.config.source
+
+interface RemoteConfigSource {
+
+ /**
+ * Gets the remotely delivered configuration that should apply to the app for the lifetime of this process, if any.
+ */
+ fun getConfig(): ConfigHttpResponse?
+
+ /**
+ * Sets the initial ETag to use for the first request, if any.
+ */
+ fun setInitialEtag(etag: String)
+}
diff --git a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/store/RemoteConfigStore.kt b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/store/RemoteConfigStore.kt
new file mode 100644
index 0000000000..ebefffa727
--- /dev/null
+++ b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/store/RemoteConfigStore.kt
@@ -0,0 +1,19 @@
+package io.embrace.android.embracesdk.internal.config.store
+
+import io.embrace.android.embracesdk.internal.config.source.ConfigHttpResponse
+
+/**
+ * Interface for storing and loading the most recently received remote configuration.
+ */
+interface RemoteConfigStore {
+
+ /**
+ * Loads the most recent remote configuration, if any.
+ */
+ fun loadResponse(): ConfigHttpResponse?
+
+ /**
+ * Saves a new remote configuration, overwriting whatever was stored before.
+ */
+ fun saveResponse(response: ConfigHttpResponse)
+}
diff --git a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/store/RemoteConfigStoreImpl.kt b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/store/RemoteConfigStoreImpl.kt
new file mode 100644
index 0000000000..b72c82d1ca
--- /dev/null
+++ b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/config/store/RemoteConfigStoreImpl.kt
@@ -0,0 +1,63 @@
+package io.embrace.android.embracesdk.internal.config.store
+
+import io.embrace.android.embracesdk.internal.config.remote.RemoteConfig
+import io.embrace.android.embracesdk.internal.config.source.ConfigHttpResponse
+import io.embrace.android.embracesdk.internal.serialization.PlatformSerializer
+import java.io.File
+
+internal class RemoteConfigStoreImpl(
+ private val serializer: PlatformSerializer,
+ storageDir: File,
+) : RemoteConfigStore {
+
+ init {
+ storageDir.mkdirs()
+ }
+
+ private val configFile = File(storageDir, "most_recent_response").apply {
+ createNewFile()
+ }
+
+ private val etagFile = File(storageDir, "etag").apply {
+ createNewFile()
+ }
+
+ override fun loadResponse(): ConfigHttpResponse? {
+ try {
+ val cfg = configFile.inputStream().buffered().use {
+ serializer.fromJson(it, RemoteConfig::class.java)
+ }
+ return ConfigHttpResponse(
+ cfg,
+ etagFile.readText().ifEmpty {
+ null
+ }
+ )
+ } catch (exc: Exception) {
+ return null
+ }
+ }
+
+ override fun saveResponse(response: ConfigHttpResponse) {
+ try {
+ configFile.outputStream().buffered().use { stream ->
+ serializer.toJson(response.cfg, RemoteConfig::class.java, stream)
+ }
+ response.etag?.let(etagFile::writeText)
+ } catch (exc: Exception) {
+ // paranoia: purge the cache
+ // to avoid the possibility of getting trapped with stale config
+ // where the SDK is disabled & persistence fails. In that scenario we prefer
+ // the default SDK behavior which will fetch the correct config eventually
+ purgeCache()
+ }
+ }
+
+ private fun purgeCache() {
+ try {
+ configFile.delete()
+ etagFile.delete()
+ } catch (ignored: Exception) {
+ }
+ }
+}
diff --git a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/injection/AndroidServicesModuleImpl.kt b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/injection/AndroidServicesModuleImpl.kt
index 807aabf0a6..ca361b6d8c 100644
--- a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/injection/AndroidServicesModuleImpl.kt
+++ b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/injection/AndroidServicesModuleImpl.kt
@@ -5,23 +5,17 @@ package io.embrace.android.embracesdk.internal.injection
import android.preference.PreferenceManager
import io.embrace.android.embracesdk.internal.prefs.EmbracePreferencesService
import io.embrace.android.embracesdk.internal.prefs.PreferencesService
-import io.embrace.android.embracesdk.internal.worker.Worker
internal class AndroidServicesModuleImpl(
initModule: InitModule,
coreModule: CoreModule,
- workerThreadModule: WorkerThreadModule,
) : AndroidServicesModule {
override val preferencesService: PreferencesService by singleton {
- val lazyPrefs = lazy {
+ EmbracePreferencesService(
PreferenceManager.getDefaultSharedPreferences(
coreModule.context
- )
- }
- EmbracePreferencesService(
- workerThreadModule.backgroundWorker(Worker.Background.IoRegWorker),
- lazyPrefs,
+ ),
initModule.clock,
initModule.jsonSerializer
)
diff --git a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/injection/AndroidServicesModuleSupplier.kt b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/injection/AndroidServicesModuleSupplier.kt
index 2ff61d7093..183dcca485 100644
--- a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/injection/AndroidServicesModuleSupplier.kt
+++ b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/injection/AndroidServicesModuleSupplier.kt
@@ -6,11 +6,9 @@ package io.embrace.android.embracesdk.internal.injection
typealias AndroidServicesModuleSupplier = (
initModule: InitModule,
coreModule: CoreModule,
- workerThreadModule: WorkerThreadModule,
) -> AndroidServicesModule
fun createAndroidServicesModule(
initModule: InitModule,
coreModule: CoreModule,
- workerThreadModule: WorkerThreadModule,
-): AndroidServicesModule = AndroidServicesModuleImpl(initModule, coreModule, workerThreadModule)
+): AndroidServicesModule = AndroidServicesModuleImpl(initModule, coreModule)
diff --git a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/injection/ConfigModule.kt b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/injection/ConfigModule.kt
index be6c8636fc..8e07e16e1c 100644
--- a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/injection/ConfigModule.kt
+++ b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/injection/ConfigModule.kt
@@ -1,7 +1,17 @@
package io.embrace.android.embracesdk.internal.injection
+import io.embrace.android.embracesdk.internal.comms.api.ApiUrlBuilder
import io.embrace.android.embracesdk.internal.config.ConfigService
+import io.embrace.android.embracesdk.internal.config.source.CombinedRemoteConfigSource
+import io.embrace.android.embracesdk.internal.config.source.RemoteConfigSource
+import io.embrace.android.embracesdk.internal.config.store.RemoteConfigStore
+import okhttp3.OkHttpClient
interface ConfigModule {
val configService: ConfigService
+ val combinedRemoteConfigSource: CombinedRemoteConfigSource?
+ val remoteConfigSource: RemoteConfigSource?
+ val remoteConfigStore: RemoteConfigStore
+ val urlBuilder: ApiUrlBuilder?
+ val okHttpClient: OkHttpClient
}
diff --git a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/injection/ConfigModuleImpl.kt b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/injection/ConfigModuleImpl.kt
index b756dead12..19846aa3a9 100644
--- a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/injection/ConfigModuleImpl.kt
+++ b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/injection/ConfigModuleImpl.kt
@@ -1,36 +1,96 @@
package io.embrace.android.embracesdk.internal.injection
import io.embrace.android.embracesdk.internal.Systrace
+import io.embrace.android.embracesdk.internal.comms.api.ApiUrlBuilder
+import io.embrace.android.embracesdk.internal.comms.api.EmbraceApiUrlBuilder
import io.embrace.android.embracesdk.internal.config.ConfigService
-import io.embrace.android.embracesdk.internal.config.EmbraceConfigService
-import io.embrace.android.embracesdk.internal.config.instrumented.InstrumentedConfig
+import io.embrace.android.embracesdk.internal.config.ConfigServiceImpl
+import io.embrace.android.embracesdk.internal.config.source.CombinedRemoteConfigSource
+import io.embrace.android.embracesdk.internal.config.source.OkHttpRemoteConfigSource
+import io.embrace.android.embracesdk.internal.config.store.RemoteConfigStore
+import io.embrace.android.embracesdk.internal.config.store.RemoteConfigStoreImpl
import io.embrace.android.embracesdk.internal.payload.AppFramework
import io.embrace.android.embracesdk.internal.worker.Worker
+import okhttp3.OkHttpClient
+import okhttp3.Protocol
+import java.io.File
+import java.util.concurrent.TimeUnit
internal class ConfigModuleImpl(
initModule: InitModule,
+ coreModule: CoreModule,
openTelemetryModule: OpenTelemetryModule,
workerThreadModule: WorkerThreadModule,
androidServicesModule: AndroidServicesModule,
framework: AppFramework,
- private val configServiceProvider: (framework: AppFramework) -> ConfigService? = { null },
- private val foregroundAction: ConfigService.() -> Unit,
- private val appIdFromConfig: String? = InstrumentedConfig.project.getAppId(),
) : ConfigModule {
+ companion object {
+ private const val DEFAULT_CONNECTION_TIMEOUT_SECONDS = 10L
+ private const val DEFAULT_READ_TIMEOUT_SECONDS = 60L
+ }
+
+ override val okHttpClient by singleton {
+ Systrace.traceSynchronous("okhttp-client-init") {
+ OkHttpClient()
+ .newBuilder()
+ .protocols(listOf(Protocol.HTTP_2, Protocol.HTTP_1_1))
+ .connectTimeout(DEFAULT_CONNECTION_TIMEOUT_SECONDS, TimeUnit.SECONDS)
+ .readTimeout(DEFAULT_READ_TIMEOUT_SECONDS, TimeUnit.SECONDS)
+ .build()
+ }
+ }
+
+ override val combinedRemoteConfigSource: CombinedRemoteConfigSource? by singleton {
+ if (initModule.onlyOtelExportEnabled()) return@singleton null
+ CombinedRemoteConfigSource(
+ store = remoteConfigStore,
+ httpSource = lazy { checkNotNull(remoteConfigSource) },
+ worker = workerThreadModule.backgroundWorker(Worker.Background.IoRegWorker),
+ )
+ }
+
override val configService: ConfigService by singleton {
Systrace.traceSynchronous("config-service-init") {
- configServiceProvider(framework)
- ?: EmbraceConfigService(
- openTelemetryCfg = openTelemetryModule.openTelemetryConfiguration,
- preferencesService = androidServicesModule.preferencesService,
- clock = initModule.clock,
- logger = initModule.logger,
- backgroundWorker = workerThreadModule.backgroundWorker(Worker.Background.IoRegWorker),
- suppliedFramework = framework,
- foregroundAction = foregroundAction,
- appIdFromConfig = appIdFromConfig,
- )
+ ConfigServiceImpl(
+ openTelemetryCfg = openTelemetryModule.openTelemetryConfiguration,
+ preferencesService = androidServicesModule.preferencesService,
+ suppliedFramework = framework,
+ instrumentedConfig = initModule.instrumentedConfig,
+ remoteConfig = combinedRemoteConfigSource?.getConfig(),
+ )
+ }
+ }
+
+ override val remoteConfigSource by singleton {
+ if (initModule.onlyOtelExportEnabled()) return@singleton null
+ OkHttpRemoteConfigSource(
+ okhttpClient = okHttpClient,
+ apiUrlBuilder = urlBuilder ?: return@singleton null,
+ serializer = initModule.jsonSerializer,
+ )
+ }
+
+ override val remoteConfigStore: RemoteConfigStore by singleton {
+ RemoteConfigStoreImpl(
+ serializer = initModule.jsonSerializer,
+ storageDir = File(coreModule.context.filesDir, "embrace_remote_config"),
+ )
+ }
+
+ override val urlBuilder: ApiUrlBuilder? by singleton {
+ if (initModule.onlyOtelExportEnabled()) return@singleton null
+ Systrace.traceSynchronous("url-builder-init") {
+ EmbraceApiUrlBuilder(
+ deviceId = androidServicesModule.preferencesService.deviceIdentifier,
+ appVersionName = coreModule.packageVersionInfo.versionName,
+ instrumentedConfig = initModule.instrumentedConfig,
+ )
}
}
+
+ private fun InitModule.onlyOtelExportEnabled(): Boolean {
+ instrumentedConfig.project.getAppId() ?: return true
+ return false
+ }
}
diff --git a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/injection/ConfigModuleSupplier.kt b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/injection/ConfigModuleSupplier.kt
index 01664e6265..3b4037730c 100644
--- a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/injection/ConfigModuleSupplier.kt
+++ b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/injection/ConfigModuleSupplier.kt
@@ -1,6 +1,5 @@
package io.embrace.android.embracesdk.internal.injection
-import io.embrace.android.embracesdk.internal.config.ConfigService
import io.embrace.android.embracesdk.internal.payload.AppFramework
/**
@@ -8,28 +7,25 @@ import io.embrace.android.embracesdk.internal.payload.AppFramework
*/
typealias ConfigModuleSupplier = (
initModule: InitModule,
+ coreModule: CoreModule,
openTelemetryModule: OpenTelemetryModule,
workerThreadModule: WorkerThreadModule,
androidServicesModule: AndroidServicesModule,
framework: AppFramework,
- configServiceProvider: (framework: AppFramework) -> ConfigService?,
- foregroundAction: ConfigService.() -> Unit,
) -> ConfigModule
fun createConfigModule(
initModule: InitModule,
+ coreModule: CoreModule,
openTelemetryModule: OpenTelemetryModule,
workerThreadModule: WorkerThreadModule,
androidServicesModule: AndroidServicesModule,
framework: AppFramework,
- configServiceProvider: (framework: AppFramework) -> ConfigService? = { null },
- foregroundAction: ConfigService.() -> Unit,
): ConfigModule = ConfigModuleImpl(
initModule,
+ coreModule,
openTelemetryModule,
workerThreadModule,
androidServicesModule,
framework,
- configServiceProvider,
- foregroundAction
)
diff --git a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/injection/CoreModuleImpl.kt b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/injection/CoreModuleImpl.kt
index be7a764304..5c1fc3e2af 100644
--- a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/injection/CoreModuleImpl.kt
+++ b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/injection/CoreModuleImpl.kt
@@ -11,6 +11,7 @@ import io.embrace.android.embracesdk.internal.registry.ServiceRegistry
class CoreModuleImpl(
ctx: Context,
+ initModule: InitModule
) : CoreModule {
override val context: Context by singleton {
@@ -39,6 +40,6 @@ class CoreModuleImpl(
}
override val buildInfoService: BuildInfoService by lazy {
- BuildInfoServiceImpl(resources, context.packageName)
+ BuildInfoServiceImpl(initModule.instrumentedConfig, resources, context.packageName)
}
}
diff --git a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/injection/CoreModuleSupplier.kt b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/injection/CoreModuleSupplier.kt
index 1ed6d12615..3a46c9c7c1 100644
--- a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/injection/CoreModuleSupplier.kt
+++ b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/injection/CoreModuleSupplier.kt
@@ -5,8 +5,12 @@ import android.content.Context
/**
* Function that returns an instance of [CoreModule]. Matches the signature of the constructor for [CoreModuleImpl]
*/
-typealias CoreModuleSupplier = (context: Context) -> CoreModule
+typealias CoreModuleSupplier = (
+ context: Context,
+ initModule: InitModule,
+) -> CoreModule
fun createCoreModule(
context: Context,
-): CoreModule = CoreModuleImpl(context)
+ initModule: InitModule
+): CoreModule = CoreModuleImpl(context, initModule)
diff --git a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/injection/DataSourceModuleImpl.kt b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/injection/DataSourceModuleImpl.kt
index d8c89a3b5f..45c0932c1e 100644
--- a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/injection/DataSourceModuleImpl.kt
+++ b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/injection/DataSourceModuleImpl.kt
@@ -2,18 +2,15 @@ package io.embrace.android.embracesdk.internal.injection
import io.embrace.android.embracesdk.internal.arch.DataCaptureOrchestrator
import io.embrace.android.embracesdk.internal.arch.EmbraceFeatureRegistry
-import io.embrace.android.embracesdk.internal.config.ConfigService
import io.embrace.android.embracesdk.internal.worker.Worker
internal class DataSourceModuleImpl(
initModule: InitModule,
- configService: ConfigService,
workerThreadModule: WorkerThreadModule,
) : DataSourceModule {
override val dataCaptureOrchestrator: DataCaptureOrchestrator by singleton {
DataCaptureOrchestrator(
- configService,
workerThreadModule.backgroundWorker(Worker.Background.NonIoRegWorker),
initModule.logger
)
diff --git a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/injection/DataSourceModuleSupplier.kt b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/injection/DataSourceModuleSupplier.kt
index 859a44cdda..d6b78b4154 100644
--- a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/injection/DataSourceModuleSupplier.kt
+++ b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/injection/DataSourceModuleSupplier.kt
@@ -1,22 +1,17 @@
package io.embrace.android.embracesdk.internal.injection
-import io.embrace.android.embracesdk.internal.config.ConfigService
-
/**
* Function that returns an instance of [DataSourceModule]. Matches the signature of the constructor for [DataSourceModuleImpl]
*/
typealias DataSourceModuleSupplier = (
initModule: InitModule,
- configService: ConfigService,
workerThreadModule: WorkerThreadModule,
) -> DataSourceModule
fun createDataSourceModule(
initModule: InitModule,
- configService: ConfigService,
workerThreadModule: WorkerThreadModule,
): DataSourceModule = DataSourceModuleImpl(
initModule,
- configService,
workerThreadModule
)
diff --git a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/injection/DeliveryModuleImpl.kt b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/injection/DeliveryModuleImpl.kt
index 98938667ad..e72a0691b1 100644
--- a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/injection/DeliveryModuleImpl.kt
+++ b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/injection/DeliveryModuleImpl.kt
@@ -1,10 +1,13 @@
package io.embrace.android.embracesdk.internal.injection
+import io.embrace.android.embracesdk.core.BuildConfig
import io.embrace.android.embracesdk.internal.comms.delivery.DeliveryService
import io.embrace.android.embracesdk.internal.comms.delivery.EmbraceDeliveryService
import io.embrace.android.embracesdk.internal.delivery.StoredTelemetryMetadata
import io.embrace.android.embracesdk.internal.delivery.caching.PayloadCachingService
import io.embrace.android.embracesdk.internal.delivery.caching.PayloadCachingServiceImpl
+import io.embrace.android.embracesdk.internal.delivery.execution.HttpUrlConnectionRequestExecutionService
+import io.embrace.android.embracesdk.internal.delivery.execution.OkHttpRequestExecutionService
import io.embrace.android.embracesdk.internal.delivery.execution.RequestExecutionService
import io.embrace.android.embracesdk.internal.delivery.intake.IntakeService
import io.embrace.android.embracesdk.internal.delivery.intake.IntakeServiceImpl
@@ -28,21 +31,11 @@ internal class DeliveryModuleImpl(
coreModule: CoreModule,
storageModule: StorageModule,
essentialServiceModule: EssentialServiceModule,
- requestExecutionServiceProvider: Provider,
- payloadStorageServiceProvider: Provider,
- cacheStorageServiceProvider: Provider,
- deliveryServiceProvider: () -> DeliveryService? = {
- val apiService = essentialServiceModule.apiService
- if (configModule.configService.isOnlyUsingOtelExporters() || apiService == null) {
- null
- } else {
- EmbraceDeliveryService(
- storageModule.deliveryCacheManager,
- apiService,
- initModule.jsonSerializer
- )
- }
- },
+ androidServicesModule: AndroidServicesModule,
+ requestExecutionServiceProvider: Provider?,
+ payloadStorageServiceProvider: Provider?,
+ cacheStorageServiceProvider: Provider?,
+ deliveryServiceProvider: Provider?
) : DeliveryModule {
private val processIdProvider = { otelModule.openTelemetryConfiguration.processIdentifier }
@@ -64,7 +57,15 @@ internal class DeliveryModuleImpl(
}
override val deliveryService: DeliveryService? by singleton {
- deliveryServiceProvider()
+ deliveryServiceProvider?.invoke() ?: if (configModule.configService.isOnlyUsingOtelExporters()) {
+ null
+ } else {
+ EmbraceDeliveryService(
+ storageModule.deliveryCacheManager,
+ essentialServiceModule.apiService ?: return@singleton null,
+ initModule.jsonSerializer
+ )
+ }
}
private val dataPersistenceWorker: PriorityWorker by singleton {
@@ -111,7 +112,7 @@ internal class DeliveryModuleImpl(
}
override val payloadStorageService: PayloadStorageService? by singleton {
- payloadStorageServiceProvider() ?: if (configModule.configService.isOnlyUsingOtelExporters()) {
+ payloadStorageServiceProvider?.invoke() ?: if (configModule.configService.isOnlyUsingOtelExporters()) {
null
} else {
PayloadStorageServiceImpl(
@@ -125,7 +126,7 @@ internal class DeliveryModuleImpl(
}
override val cacheStorageService: PayloadStorageService? by singleton {
- cacheStorageServiceProvider() ?: if (configModule.configService.isOnlyUsingOtelExporters()) {
+ cacheStorageServiceProvider?.invoke() ?: if (configModule.configService.isOnlyUsingOtelExporters()) {
null
} else {
PayloadStorageServiceImpl(
@@ -139,7 +140,31 @@ internal class DeliveryModuleImpl(
}
override val requestExecutionService: RequestExecutionService? by singleton {
- requestExecutionServiceProvider()
+ requestExecutionServiceProvider?.invoke() ?: if (configModule.configService.isOnlyUsingOtelExporters()) {
+ null
+ } else {
+ val appId = configModule.configService.appId ?: return@singleton null
+ val coreBaseUrl = configModule.urlBuilder?.baseDataUrl ?: return@singleton null
+ val lazyDeviceId = lazy(androidServicesModule.preferencesService::deviceIdentifier)
+ if (configModule.configService.autoDataCaptureBehavior.shouldUseOkHttp()) {
+ OkHttpRequestExecutionService(
+ configModule.okHttpClient,
+ coreBaseUrl,
+ lazyDeviceId,
+ appId,
+ BuildConfig.VERSION_NAME,
+ initModule.logger,
+ )
+ } else {
+ HttpUrlConnectionRequestExecutionService(
+ coreBaseUrl,
+ lazyDeviceId,
+ appId,
+ BuildConfig.VERSION_NAME,
+ initModule.logger,
+ )
+ }
+ }
}
override val schedulingService: SchedulingService? by singleton {
diff --git a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/injection/DeliveryModuleSupplier.kt b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/injection/DeliveryModuleSupplier.kt
index c8dff6de20..6b98dbef5d 100644
--- a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/injection/DeliveryModuleSupplier.kt
+++ b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/injection/DeliveryModuleSupplier.kt
@@ -16,10 +16,11 @@ typealias DeliveryModuleSupplier = (
coreModule: CoreModule,
storageModule: StorageModule,
essentialServiceModule: EssentialServiceModule,
- payloadStorageServiceProvider: Provider,
- cacheStorageServiceProvider: Provider,
- requestExecutionServiceProvider: Provider,
- deliveryServiceProvider: Provider,
+ androidServicesModule: AndroidServicesModule,
+ payloadStorageServiceProvider: Provider?,
+ cacheStorageServiceProvider: Provider?,
+ requestExecutionServiceProvider: Provider?,
+ deliveryServiceProvider: Provider?,
) -> DeliveryModule
fun createDeliveryModule(
@@ -30,10 +31,11 @@ fun createDeliveryModule(
coreModule: CoreModule,
storageModule: StorageModule,
essentialServiceModule: EssentialServiceModule,
- payloadStorageServiceProvider: Provider,
- cacheStorageServiceProvider: Provider,
- requestExecutionServiceProvider: Provider,
- deliveryServiceProvider: Provider,
+ androidServicesModule: AndroidServicesModule,
+ payloadStorageServiceProvider: Provider?,
+ cacheStorageServiceProvider: Provider?,
+ requestExecutionServiceProvider: Provider?,
+ deliveryServiceProvider: Provider?,
): DeliveryModule = DeliveryModuleImpl(
configModule,
initModule,
@@ -42,6 +44,7 @@ fun createDeliveryModule(
coreModule,
storageModule,
essentialServiceModule,
+ androidServicesModule,
requestExecutionServiceProvider,
payloadStorageServiceProvider,
cacheStorageServiceProvider,
diff --git a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/injection/EssentialServiceModule.kt b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/injection/EssentialServiceModule.kt
index d742ac7bf0..39eaed4023 100644
--- a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/injection/EssentialServiceModule.kt
+++ b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/injection/EssentialServiceModule.kt
@@ -6,7 +6,6 @@ import io.embrace.android.embracesdk.internal.capture.session.SessionPropertiesS
import io.embrace.android.embracesdk.internal.capture.user.UserService
import io.embrace.android.embracesdk.internal.comms.api.ApiClient
import io.embrace.android.embracesdk.internal.comms.api.ApiService
-import io.embrace.android.embracesdk.internal.comms.api.ApiUrlBuilder
import io.embrace.android.embracesdk.internal.comms.delivery.PendingApiCallsSender
import io.embrace.android.embracesdk.internal.session.id.SessionIdTracker
import io.embrace.android.embracesdk.internal.session.lifecycle.ActivityTracker
@@ -20,7 +19,6 @@ interface EssentialServiceModule {
val processStateService: ProcessStateService
val activityLifecycleTracker: ActivityTracker
val userService: UserService
- val urlBuilder: ApiUrlBuilder
val apiClient: ApiClient
val apiService: ApiService?
val networkConnectivityService: NetworkConnectivityService
diff --git a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/injection/EssentialServiceModuleImpl.kt b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/injection/EssentialServiceModuleImpl.kt
index f3aa4aec4a..6f50cbc6b0 100644
--- a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/injection/EssentialServiceModuleImpl.kt
+++ b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/injection/EssentialServiceModuleImpl.kt
@@ -13,11 +13,8 @@ import io.embrace.android.embracesdk.internal.capture.user.EmbraceUserService
import io.embrace.android.embracesdk.internal.capture.user.UserService
import io.embrace.android.embracesdk.internal.comms.api.ApiClient
import io.embrace.android.embracesdk.internal.comms.api.ApiClientImpl
-import io.embrace.android.embracesdk.internal.comms.api.ApiRequest
import io.embrace.android.embracesdk.internal.comms.api.ApiService
-import io.embrace.android.embracesdk.internal.comms.api.ApiUrlBuilder
import io.embrace.android.embracesdk.internal.comms.api.EmbraceApiService
-import io.embrace.android.embracesdk.internal.comms.api.EmbraceApiUrlBuilder
import io.embrace.android.embracesdk.internal.comms.delivery.EmbracePendingApiCallsSender
import io.embrace.android.embracesdk.internal.comms.delivery.PendingApiCallsSender
import io.embrace.android.embracesdk.internal.session.id.SessionIdTracker
@@ -56,25 +53,6 @@ class EssentialServiceModuleImpl(
ActivityLifecycleTracker(coreModule.application, initModule.logger)
}
- override val urlBuilder: ApiUrlBuilder by singleton {
- Systrace.traceSynchronous("url-builder-init") {
- // We use SdkEndpointBehavior and localConfig directly to avoid a circular dependency
- // but we want to access behaviors from ConfigService when possible.
- val sdkEndpointBehavior = configService.sdkEndpointBehavior
- val appId = checkNotNull(configService.appId)
- val coreBaseUrl = sdkEndpointBehavior.getData(appId)
- val configBaseUrl = sdkEndpointBehavior.getConfig(appId)
-
- EmbraceApiUrlBuilder(
- coreBaseUrl = coreBaseUrl,
- configBaseUrl = configBaseUrl,
- appId = appId,
- lazyDeviceId = lazyDeviceId,
- lazyAppVersionName = lazy { coreModule.packageVersionInfo.versionName }
- )
- }
- }
-
override val userService: UserService by singleton {
Systrace.traceSynchronous("user-service-init") {
EmbraceUserService(
@@ -111,16 +89,11 @@ class EssentialServiceModuleImpl(
EmbraceApiService(
apiClient = apiClient,
serializer = initModule.jsonSerializer,
- cachedConfigProvider = { url: String, request: ApiRequest ->
- Systrace.traceSynchronous("provide-cache-config") {
- storageModule.cache.retrieveCachedConfig(url, request)
- }
- },
priorityWorker = workerThreadModule.priorityWorker(Worker.Priority.NetworkRequestWorker),
pendingApiCallsSender = pendingApiCallsSender,
lazyDeviceId = lazyDeviceId,
appId = appId,
- urlBuilder = urlBuilder
+ urlBuilder = checkNotNull(configModule.urlBuilder)
)
}
}
diff --git a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/injection/InitModule.kt b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/injection/InitModule.kt
index 89da859bf4..d931355be7 100644
--- a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/injection/InitModule.kt
+++ b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/injection/InitModule.kt
@@ -1,6 +1,7 @@
package io.embrace.android.embracesdk.internal.injection
import io.embrace.android.embracesdk.internal.SystemInfo
+import io.embrace.android.embracesdk.internal.config.instrumented.schema.InstrumentedConfig
import io.embrace.android.embracesdk.internal.logging.EmbLogger
import io.embrace.android.embracesdk.internal.serialization.PlatformSerializer
import io.embrace.android.embracesdk.internal.telemetry.TelemetryService
@@ -33,4 +34,6 @@ interface InitModule {
* Returns the serializer used to serialize data to JSON
*/
val jsonSerializer: PlatformSerializer
+
+ val instrumentedConfig: InstrumentedConfig
}
diff --git a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/injection/InitModuleImpl.kt b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/injection/InitModuleImpl.kt
index dfe01d1b8b..9502c0c6d7 100644
--- a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/injection/InitModuleImpl.kt
+++ b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/injection/InitModuleImpl.kt
@@ -4,6 +4,8 @@ import io.embrace.android.embracesdk.internal.SystemInfo
import io.embrace.android.embracesdk.internal.clock.Clock
import io.embrace.android.embracesdk.internal.clock.NormalizedIntervalClock
import io.embrace.android.embracesdk.internal.clock.SystemClock
+import io.embrace.android.embracesdk.internal.config.instrumented.InstrumentedConfigImpl
+import io.embrace.android.embracesdk.internal.config.instrumented.schema.InstrumentedConfig
import io.embrace.android.embracesdk.internal.logging.EmbLogger
import io.embrace.android.embracesdk.internal.logging.EmbLoggerImpl
import io.embrace.android.embracesdk.internal.serialization.DecoratedSerializer
@@ -27,4 +29,6 @@ internal class InitModuleImpl(
override val jsonSerializer: PlatformSerializer by singleton {
DecoratedSerializer(EmbraceSerializer())
}
+
+ override val instrumentedConfig: InstrumentedConfig = InstrumentedConfigImpl
}
diff --git a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/injection/LogModuleImpl.kt b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/injection/LogModuleImpl.kt
index 2e02aca1a4..21fb7d63c9 100644
--- a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/injection/LogModuleImpl.kt
+++ b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/injection/LogModuleImpl.kt
@@ -30,6 +30,7 @@ internal class LogModuleImpl(
androidServicesModule.preferencesService,
{ networkCaptureDataSource },
configModule.configService,
+ configModule.urlBuilder,
initModule.jsonSerializer,
initModule.logger
)
diff --git a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/injection/StorageModule.kt b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/injection/StorageModule.kt
index 6855f156ed..22232871e8 100644
--- a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/injection/StorageModule.kt
+++ b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/injection/StorageModule.kt
@@ -1,6 +1,5 @@
package io.embrace.android.embracesdk.internal.injection
-import io.embrace.android.embracesdk.internal.comms.api.ApiResponseCache
import io.embrace.android.embracesdk.internal.comms.delivery.CacheService
import io.embrace.android.embracesdk.internal.comms.delivery.DeliveryCacheManager
import io.embrace.android.embracesdk.internal.storage.StorageService
@@ -10,7 +9,6 @@ import io.embrace.android.embracesdk.internal.storage.StorageService
*/
interface StorageModule {
val storageService: StorageService
- val cache: ApiResponseCache
val cacheService: CacheService
val deliveryCacheManager: DeliveryCacheManager
}
diff --git a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/injection/StorageModuleImpl.kt b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/injection/StorageModuleImpl.kt
index 724007130e..9c6a336db8 100644
--- a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/injection/StorageModuleImpl.kt
+++ b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/injection/StorageModuleImpl.kt
@@ -1,6 +1,5 @@
package io.embrace.android.embracesdk.internal.injection
-import io.embrace.android.embracesdk.internal.comms.api.ApiResponseCache
import io.embrace.android.embracesdk.internal.comms.delivery.CacheService
import io.embrace.android.embracesdk.internal.comms.delivery.DeliveryCacheManager
import io.embrace.android.embracesdk.internal.comms.delivery.EmbraceCacheService
@@ -25,13 +24,6 @@ internal class StorageModuleImpl(
)
}
- override val cache by singleton {
- ApiResponseCache(
- initModule.jsonSerializer,
- storageService
- )
- }
-
override val cacheService: CacheService by singleton {
EmbraceCacheService(
storageService,
diff --git a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/network/logging/EmbraceNetworkCaptureService.kt b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/network/logging/EmbraceNetworkCaptureService.kt
index d52bafad29..bed4991c1b 100644
--- a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/network/logging/EmbraceNetworkCaptureService.kt
+++ b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/network/logging/EmbraceNetworkCaptureService.kt
@@ -1,5 +1,6 @@
package io.embrace.android.embracesdk.internal.network.logging
+import io.embrace.android.embracesdk.internal.comms.api.ApiUrlBuilder
import io.embrace.android.embracesdk.internal.config.ConfigService
import io.embrace.android.embracesdk.internal.config.remote.NetworkCaptureRuleRemoteConfig
import io.embrace.android.embracesdk.internal.logging.EmbLogger
@@ -19,6 +20,7 @@ internal class EmbraceNetworkCaptureService(
private val preferencesService: PreferencesService,
private val networkCaptureDataSource: Provider,
private val configService: ConfigService,
+ private val urlBuilder: ApiUrlBuilder?,
private val serializer: PlatformSerializer,
private val logger: EmbLogger,
) : NetworkCaptureService {
@@ -41,9 +43,10 @@ internal class EmbraceNetworkCaptureService(
}
// Embrace data endpoint cannot be captured, even if there is a rule for that.
- val appId = configService.appId
- if (url.contentEquals(configService.sdkEndpointBehavior.getData(appId))) {
- return emptySet()
+ urlBuilder?.baseDataUrl?.let {
+ if (url.startsWith(it)) {
+ return emptySet()
+ }
}
val applicableRules = networkCaptureRules.filter { rule ->
diff --git a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/prefs/EmbracePreferencesService.kt b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/prefs/EmbracePreferencesService.kt
index 13b5d21c9c..280455100b 100644
--- a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/prefs/EmbracePreferencesService.kt
+++ b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/prefs/EmbracePreferencesService.kt
@@ -1,48 +1,16 @@
package io.embrace.android.embracesdk.internal.prefs
import android.content.SharedPreferences
-import io.embrace.android.embracesdk.internal.Systrace
import io.embrace.android.embracesdk.internal.clock.Clock
import io.embrace.android.embracesdk.internal.serialization.PlatformSerializer
import io.embrace.android.embracesdk.internal.utils.Uuid.getEmbUuid
-import io.embrace.android.embracesdk.internal.worker.BackgroundWorker
-import java.util.concurrent.Callable
-import java.util.concurrent.Future
-import java.util.concurrent.TimeUnit
internal class EmbracePreferencesService(
- private val backgroundWorker: BackgroundWorker,
- private val lazyPrefs: Lazy,
+ private val prefs: SharedPreferences,
private val clock: Clock,
private val serializer: PlatformSerializer,
) : PreferencesService {
- // We get SharedPreferences on a background thread because it loads data from disk
- // and can block. When client code needs to set/get a preference, getSharedPrefs() will
- // block if necessary with Future.get(). Eagerly offloading buys us more time
- // for SharedPreferences to load the File and reduces the likelihood of blocking
- // when invoked by client code.
- private val preferences: Future = Systrace.traceSynchronous("trigger-load-prefs") {
- backgroundWorker.submit(
- callable = Callable {
- Systrace.traceSynchronous("load-prefs") {
- lazyPrefs.value
- }
- }
- )
- }
-
- // fallback from this very unlikely case by just loading on the main thread
- private val prefs: SharedPreferences
- get() = try {
- Systrace.traceSynchronous("get-prefs") {
- preferences.get(2, TimeUnit.SECONDS)
- }
- } catch (exc: Throwable) {
- // fallback from this very unlikely case by just loading on the main thread
- lazyPrefs.value
- }
-
private fun SharedPreferences.getStringPreference(key: String): String? {
return getString(key, null)
}
@@ -159,10 +127,6 @@ internal class EmbracePreferencesService(
}
set(value) = prefs.setStringPreference(DEVICE_IDENTIFIER_KEY, value)
- override var sdkDisabled: Boolean
- get() = prefs.getBooleanPreference(SDK_DISABLED_KEY, false)
- set(value) = prefs.setBooleanPreference(SDK_DISABLED_KEY, value)
-
override var userPayer: Boolean
get() = prefs.getBooleanPreference(USER_IS_PAYER_KEY, false)
set(value) = prefs.setBooleanPreference(USER_IS_PAYER_KEY, value)
@@ -191,10 +155,6 @@ internal class EmbracePreferencesService(
get() = prefs.getLongPreference(SDK_CONFIG_FETCHED_TIMESTAMP)
set(value) = prefs.setLongPreference(SDK_CONFIG_FETCHED_TIMESTAMP, value)
- override var userMessageNeedsRetry: Boolean
- get() = prefs.getBooleanPreference(LAST_USER_MESSAGE_FAILED_KEY, false)
- set(value) = prefs.setBooleanPreference(LAST_USER_MESSAGE_FAILED_KEY, value)
-
override fun incrementAndGetSessionNumber(): Int {
return incrementAndGetOrdinal(LAST_SESSION_NUMBER_KEY)
}
@@ -275,10 +235,6 @@ internal class EmbracePreferencesService(
get() = prefs.getStringPreference(SCREEN_RESOLUTION_KEY)
set(value) = prefs.setStringPreference(SCREEN_RESOLUTION_KEY, value)
- override var backgroundActivityEnabled: Boolean
- get() = prefs.getBooleanPreference(BACKGROUND_ACTIVITY_ENABLED_KEY, false)
- set(value) = prefs.setBooleanPreference(BACKGROUND_ACTIVITY_ENABLED_KEY, value)
-
override var applicationExitInfoHistory: Set?
get() = prefs.getStringSet(AEI_HASH_CODES, null)
set(value) = prefs.setArrayPreference(AEI_HASH_CODES, value)
@@ -309,8 +265,6 @@ internal class EmbracePreferencesService(
}
companion object {
- internal const val SDK_STARTUP_IN_PROGRESS = "startup_entered"
- internal const val SDK_STARTUP_COMPLETED = "startup_completed"
private const val DEVICE_IDENTIFIER_KEY = "io.embrace.deviceid"
private const val PREVIOUS_APP_VERSION_KEY = "io.embrace.lastappversion"
private const val PREVIOUS_OS_VERSION_KEY = "io.embrace.lastosversion"
@@ -320,7 +274,6 @@ internal class EmbracePreferencesService(
private const val USER_USERNAME_KEY = "io.embrace.username"
private const val USER_IS_PAYER_KEY = "io.embrace.userispayer"
private const val USER_PERSONAS_KEY = "io.embrace.userpersonas"
- private const val LAST_USER_MESSAGE_FAILED_KEY = "io.embrace.userupdatefailed"
private const val LAST_SESSION_NUMBER_KEY = "io.embrace.sessionnumber"
private const val LAST_BACKGROUND_ACTIVITY_NUMBER_KEY = "io.embrace.bgactivitynumber"
private const val LAST_CRASH_NUMBER_KEY = "io.embrace.crashnumber"
@@ -338,9 +291,7 @@ internal class EmbracePreferencesService(
private const val EMBRACE_FLUTTER_SDK_VERSION_KEY = "io.embrace.flutter.sdk.version"
private const val IS_JAILBROKEN_KEY = "io.embrace.is_jailbroken"
private const val SCREEN_RESOLUTION_KEY = "io.embrace.screen.resolution"
- private const val BACKGROUND_ACTIVITY_ENABLED_KEY = "io.embrace.bgactivitycapture"
private const val NETWORK_CAPTURE_RULE_PREFIX_KEY = "io.embrace.networkcapturerule"
- private const val SDK_DISABLED_KEY = "io.embrace.disabled"
private const val SDK_CONFIG_FETCHED_TIMESTAMP = "io.embrace.sdkfetchedtimestamp"
private const val AEI_HASH_CODES = "io.embrace.aeiHashCode"
}
diff --git a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/prefs/PreferencesService.kt b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/prefs/PreferencesService.kt
index f3a7e27e60..9f29f26de5 100644
--- a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/prefs/PreferencesService.kt
+++ b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/prefs/PreferencesService.kt
@@ -22,11 +22,6 @@ interface PreferencesService {
*/
var deviceIdentifier: String
- /**
- * If the sdk is disabled
- */
- var sdkDisabled: Boolean
-
/**
* If the user is payer
*/
@@ -62,11 +57,6 @@ interface PreferencesService {
*/
var lastConfigFetchDate: Long?
- /**
- * If the user message needs to retry send
- */
- var userMessageNeedsRetry: Boolean
-
/**
* Increments and returns the session number ordinal. This is an integer that increments
* at the start of every session. This allows us to check the % of sessions that didn't get
@@ -155,11 +145,6 @@ interface PreferencesService {
*/
var screenResolution: String?
- /**
- * If background activity capture is enabled
- */
- var backgroundActivityEnabled: Boolean
-
/**
* Set of hashcodes derived from ApplicationExitInfo objects
*/
diff --git a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/session/message/PayloadFactoryImpl.kt b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/session/message/PayloadFactoryImpl.kt
index 5ae5f5d991..f627c491ce 100644
--- a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/session/message/PayloadFactoryImpl.kt
+++ b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/session/message/PayloadFactoryImpl.kt
@@ -195,5 +195,5 @@ internal class PayloadFactoryImpl(
)
}
- private fun isBackgroundActivityEnabled(): Boolean = configService.isBackgroundActivityCaptureEnabled()
+ private fun isBackgroundActivityEnabled(): Boolean = configService.backgroundActivityBehavior.isBackgroundActivityCaptureEnabled()
}
diff --git a/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/arch/DataCaptureOrchestratorTest.kt b/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/arch/DataCaptureOrchestratorTest.kt
index 0a37a1e48e..426d6b21cf 100644
--- a/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/arch/DataCaptureOrchestratorTest.kt
+++ b/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/arch/DataCaptureOrchestratorTest.kt
@@ -39,24 +39,11 @@ internal class DataCaptureOrchestratorTest {
configService = FakeConfigService()
executorService = BlockingScheduledExecutorService(blockingMode = false)
orchestrator = DataCaptureOrchestrator(
- configService,
BackgroundWorker(executorService),
EmbLoggerImpl(),
)
}
- @Test
- fun `config changes are propagated`() {
- orchestrator.add(syncDataSource)
- assertEquals(0, dataSource.enableDataCaptureCount)
- orchestrator.currentSessionType = SessionType.FOREGROUND
- assertEquals(1, dataSource.enableDataCaptureCount)
-
- enabled = false
- configService.updateListeners()
- assertEquals(1, dataSource.disableDataCaptureCount)
- }
-
@Test
fun `session type change is propagated`() {
orchestrator.add(syncDataSource)
@@ -65,23 +52,6 @@ internal class DataCaptureOrchestratorTest {
assertEquals(1, dataSource.enableDataCaptureCount)
}
- @Test
- fun `async config change`() {
- orchestrator.add(asyncDataSource)
- executorService.blockingMode = true
-
- orchestrator.currentSessionType = SessionType.FOREGROUND
- assertEquals(0, dataSource.enableDataCaptureCount)
- executorService.runCurrentlyBlocked()
- assertEquals(1, dataSource.enableDataCaptureCount)
-
- enabled = false
- configService.updateListeners()
- assertEquals(0, dataSource.disableDataCaptureCount)
- executorService.runCurrentlyBlocked()
- assertEquals(1, dataSource.disableDataCaptureCount)
- }
-
@Test
fun `async session change`() {
orchestrator.add(asyncDataSource)
diff --git a/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/arch/DataSourceStateTest.kt b/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/arch/DataSourceStateTest.kt
index c9e41f82f2..0c54d86ee4 100644
--- a/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/arch/DataSourceStateTest.kt
+++ b/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/arch/DataSourceStateTest.kt
@@ -21,15 +21,9 @@ internal class DataSourceStateTest {
configGate = { true }
)
- // data source not retrievable if not session type is null
+ // data source not retrievable if the session type is null
assertNull(state.dataSource)
- // data capture is enabled by default.
- state.onConfigChange()
- state.currentSessionType = null
- assertEquals(0, source.enableDataCaptureCount)
- assertEquals(0, source.disableDataCaptureCount)
-
// data capture enabled for a session
state.currentSessionType = SessionType.FOREGROUND
assertSame(source, state.dataSource)
@@ -64,7 +58,7 @@ internal class DataSourceStateTest {
}
@Test
- fun `test config gate enabled by default`() {
+ fun `test config gate enabled`() {
val source = FakeDataSource(RuntimeEnvironment.getApplication())
DataSourceState(
factory = { source },
@@ -79,47 +73,18 @@ internal class DataSourceStateTest {
}
@Test
- fun `test config gate affects data capture`() {
+ fun `test config gate disabled`() {
val source = FakeDataSource(RuntimeEnvironment.getApplication())
- var enabled = false
- val state = DataSourceState(
+ DataSourceState(
factory = { source },
- configGate = { enabled },
+ configGate = { false },
).apply {
currentSessionType = SessionType.FOREGROUND
}
- // data source not retrievable if disabled
- assertNull(state.dataSource)
-
- // data capture is disabled by default.
+ // data capture is enabled by default.
assertEquals(0, source.enableDataCaptureCount)
assertEquals(0, source.disableDataCaptureCount)
-
- // enabling the config gate should enable data capture
- enabled = true
- state.onConfigChange()
- assertEquals(1, source.enableDataCaptureCount)
- assertEquals(0, source.disableDataCaptureCount)
-
- // another config change should not reregister listeners
- state.onConfigChange()
- assertEquals(1, source.enableDataCaptureCount)
- assertEquals(0, source.disableDataCaptureCount)
-
- // deregistering works
- enabled = false
- state.onConfigChange()
- assertEquals(1, source.enableDataCaptureCount)
- assertEquals(1, source.disableDataCaptureCount)
-
- // functions can be called multiple times without issue
- enabled = true
- state.onConfigChange()
- enabled = false
- state.onConfigChange()
- assertEquals(2, source.enableDataCaptureCount)
- assertEquals(2, source.disableDataCaptureCount)
}
@Test
diff --git a/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/arch/schema/TelemetryAttributesTest.kt b/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/arch/schema/TelemetryAttributesTest.kt
index 50beb6946b..7707dc192b 100644
--- a/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/arch/schema/TelemetryAttributesTest.kt
+++ b/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/arch/schema/TelemetryAttributesTest.kt
@@ -105,14 +105,12 @@ internal class TelemetryAttributesTest {
fun `log properties and session properties are not included in the attributes`() {
val configService = FakeConfigService(
sessionBehavior = createSessionBehavior(
- remoteCfg = {
- RemoteConfig(
- sessionConfig = SessionRemoteConfig(
- fullSessionEvents = setOf(),
- sessionComponents = setOf()
- )
+ remoteCfg = RemoteConfig(
+ sessionConfig = SessionRemoteConfig(
+ fullSessionEvents = setOf(),
+ sessionComponents = setOf()
)
- }
+ )
)
)
sessionPropertiesService.addProperty("perm", "permVal", true)
@@ -133,14 +131,12 @@ internal class TelemetryAttributesTest {
fun `log properties and session properties are included in the attributes`() {
val configService = FakeConfigService(
sessionBehavior = createSessionBehavior(
- remoteCfg = {
- RemoteConfig(
- sessionConfig = SessionRemoteConfig(
- fullSessionEvents = setOf(),
- sessionComponents = setOf("s_props", "log_pr")
- )
+ remoteCfg = RemoteConfig(
+ sessionConfig = SessionRemoteConfig(
+ fullSessionEvents = setOf(),
+ sessionComponents = setOf("s_props", "log_pr")
)
- }
+ )
)
)
sessionPropertiesService.addProperty("perm", "permVal", true)
diff --git a/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/capture/session/EmbraceSessionPropertiesTest.kt b/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/capture/session/EmbraceSessionPropertiesTest.kt
index a4a80a65e1..8aa13c942b 100644
--- a/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/capture/session/EmbraceSessionPropertiesTest.kt
+++ b/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/capture/session/EmbraceSessionPropertiesTest.kt
@@ -10,7 +10,6 @@ import io.embrace.android.embracesdk.fakes.FakeClock
import io.embrace.android.embracesdk.fakes.FakeConfigService
import io.embrace.android.embracesdk.fakes.FakeCurrentSessionSpan
import io.embrace.android.embracesdk.fakes.behavior.FakeSessionBehavior
-import io.embrace.android.embracesdk.fakes.fakeBackgroundWorker
import io.embrace.android.embracesdk.internal.prefs.EmbracePreferencesService
import io.embrace.android.embracesdk.internal.prefs.PreferencesService
import io.embrace.android.embracesdk.internal.serialization.EmbraceSerializer
@@ -43,11 +42,10 @@ internal class EmbraceSessionPropertiesTest {
@Before
fun setUp() {
- val worker = fakeBackgroundWorker()
context = ApplicationProvider.getApplicationContext()
- val prefs = lazy { PreferenceManager.getDefaultSharedPreferences(context) }
+ val prefs = PreferenceManager.getDefaultSharedPreferences(context)
preferencesService =
- EmbracePreferencesService(worker, prefs, fakeClock, EmbraceSerializer())
+ EmbracePreferencesService(prefs, fakeClock, EmbraceSerializer())
configService = FakeConfigService(
sessionBehavior = FakeSessionBehavior(MAX_SESSION_PROPERTIES_DEFAULT)
diff --git a/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/capture/session/SessionPropertiesServiceImplTest.kt b/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/capture/session/SessionPropertiesServiceImplTest.kt
index 22d3276dad..406a45f15d 100644
--- a/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/capture/session/SessionPropertiesServiceImplTest.kt
+++ b/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/capture/session/SessionPropertiesServiceImplTest.kt
@@ -3,6 +3,8 @@ package io.embrace.android.embracesdk.internal.capture.session
import io.embrace.android.embracesdk.fakes.FakeConfigService
import io.embrace.android.embracesdk.fakes.FakeCurrentSessionSpan
import io.embrace.android.embracesdk.fakes.FakePreferenceService
+import io.embrace.android.embracesdk.fakes.config.FakeInstrumentedConfig
+import io.embrace.android.embracesdk.fakes.config.FakeRedactionConfig
import io.embrace.android.embracesdk.internal.config.behavior.REDACTED_LABEL
import io.embrace.android.embracesdk.internal.config.behavior.SensitiveKeysBehaviorImpl
import org.junit.Assert.assertEquals
@@ -21,7 +23,9 @@ internal class SessionPropertiesServiceImplTest {
fun setUp() {
val fakeConfigService =
FakeConfigService(
- sensitiveKeysBehavior = SensitiveKeysBehaviorImpl(listOf("password"))
+ sensitiveKeysBehavior = SensitiveKeysBehaviorImpl(
+ FakeInstrumentedConfig(redaction = FakeRedactionConfig(sensitiveKeys = listOf("password"))),
+ )
)
fakeCurrentSessionSpan = FakeCurrentSessionSpan()
service = SessionPropertiesServiceImpl(
diff --git a/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/comms/api/ApiRequestMapperTest.kt b/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/comms/api/ApiRequestMapperTest.kt
index 27065ba416..de8105a82a 100644
--- a/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/comms/api/ApiRequestMapperTest.kt
+++ b/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/comms/api/ApiRequestMapperTest.kt
@@ -1,5 +1,7 @@
package io.embrace.android.embracesdk.internal.comms.api
+import io.embrace.android.embracesdk.fakes.config.FakeBaseUrlConfig
+import io.embrace.android.embracesdk.fakes.config.FakeInstrumentedConfig
import io.embrace.android.embracesdk.internal.payload.Attribute
import io.embrace.android.embracesdk.internal.payload.Envelope
import io.embrace.android.embracesdk.internal.payload.Log
@@ -19,11 +21,14 @@ internal class ApiRequestMapperTest {
private val deviceId = lazy { "deviceId" }
private val mapper = ApiRequestMapper(
urlBuilder = EmbraceApiUrlBuilder(
- BASE_URL,
- CONFIG_URL,
- "appId",
- deviceId,
- lazy { "appVersionName" }
+ deviceId.value,
+ "1.0",
+ FakeInstrumentedConfig(
+ baseUrls = FakeBaseUrlConfig(
+ configImpl = CONFIG_URL,
+ dataImpl = BASE_URL
+ )
+ )
),
lazyDeviceId = deviceId,
appId = "appId"
diff --git a/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/comms/api/CachedConfigTest.kt b/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/comms/api/CachedConfigTest.kt
deleted file mode 100644
index e7d6810714..0000000000
--- a/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/comms/api/CachedConfigTest.kt
+++ /dev/null
@@ -1,17 +0,0 @@
-package io.embrace.android.embracesdk.internal.comms.api
-
-import io.embrace.android.embracesdk.internal.config.remote.RemoteConfig
-import org.junit.Assert.assertFalse
-import org.junit.Assert.assertTrue
-import org.junit.Test
-
-internal class CachedConfigTest {
-
- @Test
- fun isValid() {
- assertFalse(CachedConfig(null, null).isValid())
- assertFalse(CachedConfig(RemoteConfig(), null).isValid())
- assertFalse(CachedConfig(null, "ba09cc").isValid())
- assertTrue(CachedConfig(RemoteConfig(), "ba09cc").isValid())
- }
-}
diff --git a/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/comms/api/EmbraceApiServiceTest.kt b/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/comms/api/EmbraceApiServiceTest.kt
index db8ca53ac9..f293e5b210 100644
--- a/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/comms/api/EmbraceApiServiceTest.kt
+++ b/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/comms/api/EmbraceApiServiceTest.kt
@@ -1,16 +1,14 @@
package io.embrace.android.embracesdk.internal.comms.api
-import io.embrace.android.embracesdk.ResourceReader
import io.embrace.android.embracesdk.concurrency.BlockingScheduledExecutorService
import io.embrace.android.embracesdk.fakes.FakeApiClient
import io.embrace.android.embracesdk.fakes.FakeDeliveryCacheManager
import io.embrace.android.embracesdk.fakes.FakePendingApiCallsSender
+import io.embrace.android.embracesdk.fakes.config.FakeInstrumentedConfig
import io.embrace.android.embracesdk.internal.TypeUtils
-import io.embrace.android.embracesdk.internal.comms.api.ApiClient.Companion.NO_HTTP_RESPONSE
import io.embrace.android.embracesdk.internal.comms.delivery.DeliveryCacheManager
import io.embrace.android.embracesdk.internal.comms.delivery.NetworkStatus
import io.embrace.android.embracesdk.internal.compression.ConditionalGzipOutputStream
-import io.embrace.android.embracesdk.internal.config.remote.RemoteConfig
import io.embrace.android.embracesdk.internal.payload.Attribute
import io.embrace.android.embracesdk.internal.payload.Envelope
import io.embrace.android.embracesdk.internal.payload.Log
@@ -24,7 +22,6 @@ import org.junit.Assert.assertArrayEquals
import org.junit.Assert.assertEquals
import org.junit.Assert.assertFalse
import org.junit.Assert.assertNull
-import org.junit.Assert.assertSame
import org.junit.Assert.assertTrue
import org.junit.Before
import org.junit.Test
@@ -42,23 +39,17 @@ internal class EmbraceApiServiceTest {
private lateinit var fakeApiClient: FakeApiClient
private lateinit var fakeCacheManager: DeliveryCacheManager
private lateinit var testScheduledExecutor: BlockingScheduledExecutorService
- private lateinit var cachedConfig: CachedConfig
private lateinit var apiService: EmbraceApiService
private lateinit var fakePendingApiCallsSender: FakePendingApiCallsSender
@Before
fun setUp() {
apiUrlBuilder = EmbraceApiUrlBuilder(
- coreBaseUrl = "https://a-$fakeAppId.data.emb-api.com",
- configBaseUrl = "https://a-$fakeAppId.config.emb-api.com",
- appId = fakeAppId,
- lazyDeviceId = lazy { fakeDeviceId },
- lazyAppVersionName = lazy { fakeAppVersionName }
+ deviceId = fakeDeviceId,
+ appVersionName = fakeAppVersionName,
+ instrumentedConfig = FakeInstrumentedConfig()
)
fakeApiClient = FakeApiClient()
- cachedConfig = CachedConfig(
- remoteConfig = RemoteConfig()
- )
testScheduledExecutor = BlockingScheduledExecutorService(blockingMode = false)
fakeCacheManager = FakeDeliveryCacheManager()
fakePendingApiCallsSender = FakePendingApiCallsSender()
@@ -72,78 +63,6 @@ internal class EmbraceApiServiceTest {
}
}
- @Test
- fun `test getConfig returns correct values in Response`() {
- fakeApiClient.queueResponse(
- ApiResponse.Success(
- headers = emptyMap(),
- body = defaultConfigResponseBody
- )
- )
-
- val remoteConfig = apiService.getConfig()
-
- // verify a few fields were serialized correctly.
- checkNotNull(remoteConfig)
- assertTrue(checkNotNull(remoteConfig.sessionConfig?.isEnabled))
- assertEquals(100, remoteConfig.threshold)
- }
-
- @Test(expected = IllegalStateException::class)
- fun `getConfig throws an exception when receiving ApiResponse_Incomplete`() {
- val incompleteResponse: ApiResponse.Incomplete = ApiResponse.Incomplete(
- IllegalStateException("Connection failed")
- )
- fakeApiClient.queueResponse(incompleteResponse)
- apiService.getConfig()
- }
-
- @Test
- fun `cached remote config returned when 304 received`() {
- fakeApiClient.queueResponse(
- ApiResponse.NotModified
- )
- assertEquals(cachedConfig.remoteConfig, apiService.getConfig())
- }
-
- @Test
- fun `getConfig did not complete returns a null config`() {
- fakeApiClient.queueResponse(
- ApiResponse.Failure(
- code = NO_HTTP_RESPONSE,
- headers = emptyMap()
- )
- )
- assertNull(apiService.getConfig())
- }
-
- @Test
- fun `getConfig results in unexpected response code returns a null config`() {
- fakeApiClient.queueResponse(
- ApiResponse.Failure(
- code = 400,
- headers = emptyMap()
- )
- )
- assertNull(apiService.getConfig())
- }
-
- @Test
- fun testGetConfigWithMatchingEtag() {
- val cfg = RemoteConfig()
- cachedConfig = CachedConfig(cfg, "my_etag")
- fakeApiClient.queueResponse(
- ApiResponse.NotModified
- )
- val remoteConfig = apiService.getConfig()
- assertSame(cfg, remoteConfig)
- }
-
- @Test
- fun `getCacheConfig returns what the provider provides`() {
- assertEquals(apiService.getCachedConfig(), cachedConfig)
- }
-
@Test
fun `send v2 session`() {
fakeApiClient.queueResponse(successfulPostResponse)
@@ -216,23 +135,6 @@ internal class EmbraceApiServiceTest {
assertArrayEquals(getGenericsExpectedPayloadSerialized(logsEnvelope, type), payload)
}
- @Test
- fun `validate all API endpoint URLs`() {
- Endpoint.values().forEach {
- if (it.version == "v1") {
- assertEquals(
- "https://a-$fakeAppId.data.emb-api.com/v1/log/${it.path}",
- apiUrlBuilder.getEmbraceUrlWithSuffix("v1", it.path)
- )
- } else {
- assertEquals(
- "https://a-$fakeAppId.data.emb-api.com/v2/${it.path}",
- apiUrlBuilder.getEmbraceUrlWithSuffix("v2", it.path)
- )
- }
- }
- }
-
@Test
fun `network request runnable is used`() {
initApiService()
@@ -430,7 +332,6 @@ internal class EmbraceApiServiceTest {
apiService = EmbraceApiService(
apiClient = fakeApiClient,
serializer = serializer,
- cachedConfigProvider = { _, _ -> cachedConfig },
priorityWorker = PriorityWorker(testScheduledExecutor),
pendingApiCallsSender = fakePendingApiCallsSender,
lazyDeviceId = lazy { fakeDeviceId },
@@ -441,11 +342,9 @@ internal class EmbraceApiServiceTest {
}
companion object {
- private const val fakeAppId = "A1B2C"
+ private const val fakeAppId = "abcde"
private const val fakeDeviceId = "ajflkadsflkadslkfjds"
private const val fakeAppVersionName = "6.1.0"
- private val defaultConfigResponseBody =
- ResourceReader.readResourceAsText("remote_config_response.json")
private val successfulPostResponse = ApiResponse.Success(
headers = emptyMap(),
body = ""
diff --git a/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/comms/api/EmbraceApiUrlBuilderTest.kt b/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/comms/api/EmbraceApiUrlBuilderTest.kt
index 5c33f75f9e..138998099a 100644
--- a/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/comms/api/EmbraceApiUrlBuilderTest.kt
+++ b/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/comms/api/EmbraceApiUrlBuilderTest.kt
@@ -1,13 +1,11 @@
package io.embrace.android.embracesdk.internal.comms.api
-import io.embrace.android.embracesdk.fakes.createSdkEndpointBehavior
-import io.mockk.unmockkAll
-import org.junit.After
+import io.embrace.android.embracesdk.fakes.config.FakeInstrumentedConfig
import org.junit.Assert.assertEquals
import org.junit.Before
import org.junit.Test
-private const val APP_ID = "o0o0o"
+private const val APP_ID = "abcde"
private const val APP_VERSION_NAME = "1.0.0"
private const val DEVICE_ID = "07D85B44E4E245F4A30E559BFC0D07FF"
@@ -16,36 +14,27 @@ internal class EmbraceApiUrlBuilderTest {
@Before
fun setup() {
- val baseUrlLocalConfig = createSdkEndpointBehavior()
-
apiUrlBuilder = EmbraceApiUrlBuilder(
- coreBaseUrl = baseUrlLocalConfig.getData(APP_ID),
- configBaseUrl = baseUrlLocalConfig.getConfig(APP_ID),
- appId = APP_ID,
- lazyDeviceId = lazy { DEVICE_ID },
- lazyAppVersionName = lazy { APP_VERSION_NAME },
+ deviceId = DEVICE_ID,
+ appVersionName = APP_VERSION_NAME,
+ FakeInstrumentedConfig()
)
}
- @After
- fun tearDown() {
- unmockkAll()
- }
-
@Test
fun testUrls() {
assertEquals(
"https://a-$APP_ID.config.emb-api.com/v2/config?appId=$APP_ID&osVersion=0.0.0" +
"&appVersion=$APP_VERSION_NAME&deviceId=$DEVICE_ID",
- apiUrlBuilder.getConfigUrl()
+ apiUrlBuilder.resolveUrl(Endpoint.CONFIG)
)
assertEquals(
- "https://a-$APP_ID.data.emb-api.com/v1/log/suffix",
- apiUrlBuilder.getEmbraceUrlWithSuffix("v1", "suffix")
+ "https://a-$APP_ID.data.emb-api.com/v2/logs",
+ apiUrlBuilder.resolveUrl(Endpoint.LOGS)
)
assertEquals(
- "https://a-$APP_ID.data.emb-api.com/v2/suffix",
- apiUrlBuilder.getEmbraceUrlWithSuffix("v2", "suffix")
+ "https://a-$APP_ID.data.emb-api.com/v2/spans",
+ apiUrlBuilder.resolveUrl(Endpoint.SESSIONS)
)
}
}
diff --git a/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/comms/delivery/EmbracePendingApiCallsSenderTest.kt b/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/comms/delivery/EmbracePendingApiCallsSenderTest.kt
index b2c880ad0a..5d80158e77 100644
--- a/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/comms/delivery/EmbracePendingApiCallsSenderTest.kt
+++ b/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/comms/delivery/EmbracePendingApiCallsSenderTest.kt
@@ -2,6 +2,7 @@ package io.embrace.android.embracesdk.internal.comms.delivery
import io.embrace.android.embracesdk.concurrency.BlockingScheduledExecutorService
import io.embrace.android.embracesdk.fakes.FakeClock
+import io.embrace.android.embracesdk.fakes.config.FakeInstrumentedConfig
import io.embrace.android.embracesdk.internal.comms.api.ApiRequest
import io.embrace.android.embracesdk.internal.comms.api.ApiRequestMapper
import io.embrace.android.embracesdk.internal.comms.api.ApiRequestUrl
@@ -251,11 +252,9 @@ internal class EmbracePendingApiCallsSenderTest {
repeat(15) {
val mapper = ApiRequestMapper(
EmbraceApiUrlBuilder(
- "https://data.emb-api.com/$it",
- "https://config.emb-api.com",
- "appId",
- lazy { "deviceId" },
- lazy { "appVersionName" }
+ "deviceId",
+ "appVersionName",
+ FakeInstrumentedConfig()
),
lazy { "deviceId" },
"appId"
@@ -271,22 +270,20 @@ internal class EmbracePendingApiCallsSenderTest {
// verify logs were added to the queue, and oldest added requests are dropped
assertEquals(
- "https://data.emb-api.com/5/v2/logs",
+ "https://a-abcde.data.emb-api.com/v2/logs",
queue.pollNextPendingApiCall()?.apiRequest?.url?.url
)
assertEquals(
- "https://data.emb-api.com/6/v2/logs",
+ "https://a-abcde.data.emb-api.com/v2/logs",
queue.pollNextPendingApiCall()?.apiRequest?.url?.url
)
// now add some sessions for retry and verify they are returned first
val mapper = ApiRequestMapper(
EmbraceApiUrlBuilder(
- "https://data.emb-api.com/session",
- "https://config.emb-api.com",
- "appId",
- lazy { "deviceId" },
- lazy { "appVersionName" }
+ "deviceId",
+ "appVersionName",
+ FakeInstrumentedConfig()
),
lazy { "deviceId" },
"appId"
diff --git a/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/comms/delivery/PendingApiCallsTest.kt b/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/comms/delivery/PendingApiCallsTest.kt
index 86d2068eec..7332f8e719 100644
--- a/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/comms/delivery/PendingApiCallsTest.kt
+++ b/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/comms/delivery/PendingApiCallsTest.kt
@@ -181,8 +181,8 @@ internal class PendingApiCallsTest {
private fun Endpoint.getMaxPendingApiCalls(): Int {
return when (this) {
Endpoint.LOGS -> 10
- Endpoint.UNKNOWN -> 50
Endpoint.SESSIONS -> 100
+ else -> 50
}
}
}
diff --git a/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/config/ConfigServiceImplTest.kt b/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/config/ConfigServiceImplTest.kt
new file mode 100644
index 0000000000..ec62bc11f9
--- /dev/null
+++ b/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/config/ConfigServiceImplTest.kt
@@ -0,0 +1,204 @@
+package io.embrace.android.embracesdk.internal.config
+
+import io.embrace.android.embracesdk.concurrency.BlockingScheduledExecutorService
+import io.embrace.android.embracesdk.fakes.FakeClock
+import io.embrace.android.embracesdk.fakes.FakeLogRecordExporter
+import io.embrace.android.embracesdk.fakes.FakePreferenceService
+import io.embrace.android.embracesdk.fakes.FakeProcessStateService
+import io.embrace.android.embracesdk.fakes.config.FakeInstrumentedConfig
+import io.embrace.android.embracesdk.fakes.config.FakeProjectConfig
+import io.embrace.android.embracesdk.internal.SystemInfo
+import io.embrace.android.embracesdk.internal.config.behavior.BehaviorThresholdCheck
+import io.embrace.android.embracesdk.internal.config.remote.RemoteConfig
+import io.embrace.android.embracesdk.internal.logging.EmbLogger
+import io.embrace.android.embracesdk.internal.logging.EmbLoggerImpl
+import io.embrace.android.embracesdk.internal.logs.LogSinkImpl
+import io.embrace.android.embracesdk.internal.opentelemetry.OpenTelemetryConfiguration
+import io.embrace.android.embracesdk.internal.payload.AppFramework
+import io.embrace.android.embracesdk.internal.prefs.PreferencesService
+import io.embrace.android.embracesdk.internal.session.lifecycle.ProcessStateService
+import io.embrace.android.embracesdk.internal.spans.SpanSinkImpl
+import io.embrace.android.embracesdk.internal.worker.BackgroundWorker
+import io.mockk.clearAllMocks
+import io.mockk.mockkStatic
+import io.mockk.unmockkAll
+import org.junit.After
+import org.junit.AfterClass
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertFalse
+import org.junit.Assert.assertNotNull
+import org.junit.Assert.assertTrue
+import org.junit.Before
+import org.junit.BeforeClass
+import org.junit.Test
+
+internal class ConfigServiceImplTest {
+
+ private lateinit var fakePreferenceService: PreferencesService
+ private lateinit var service: ConfigServiceImpl
+ private lateinit var worker: BackgroundWorker
+ private lateinit var executor: BlockingScheduledExecutorService
+ private lateinit var thresholdCheck: BehaviorThresholdCheck
+
+ companion object {
+ private lateinit var remoteConfig: RemoteConfig
+ private lateinit var processStateService: ProcessStateService
+ private lateinit var logger: EmbLogger
+ private lateinit var fakeClock: FakeClock
+
+ /**
+ * Setup before all tests get executed. Create mocks here.
+ */
+ @BeforeClass
+ @JvmStatic
+ fun setupBeforeAll() {
+ mockkStatic(RemoteConfig::class)
+ remoteConfig = RemoteConfig()
+ processStateService = FakeProcessStateService()
+ fakeClock = FakeClock()
+ logger = EmbLoggerImpl()
+ }
+
+ /**
+ * Setup after all tests get executed. Un-mock all here.
+ */
+ @AfterClass
+ @JvmStatic
+ fun tearDownAfterAll() {
+ unmockkAll()
+ }
+ }
+
+ /**
+ * Setup before each test.
+ */
+ @Before
+ fun setup() {
+ fakeClock.setCurrentTime(1000000000000)
+ fakePreferenceService = FakePreferenceService(deviceIdentifier = "07D85B44E4E245F4A30E559BFC0D07FF")
+ executor = BlockingScheduledExecutorService(blockingMode = false)
+ worker = BackgroundWorker(executor)
+ service = createService()
+ assertFalse(service.isOnlyUsingOtelExporters())
+ }
+
+ /**
+ * Setup after each test. Clean mocks content.
+ */
+ @After
+ fun tearDown() {
+ clearAllMocks()
+ }
+
+ @Suppress("DEPRECATION")
+ @Test
+ fun `test legacy normalized DeviceId`() {
+ fakePreferenceService.deviceIdentifier = "07D85B44E4E245F4A30E559BFC0D0700"
+ assertEquals(0.0, thresholdCheck.getNormalizedDeviceId().toDouble(), 0.01)
+
+ fakePreferenceService.deviceIdentifier = "07D85B44E4E245F4A30E559BFC0D07FF"
+ assertEquals(100.0, thresholdCheck.getNormalizedDeviceId().toDouble(), 0.01)
+
+ fakePreferenceService.deviceIdentifier = "07D85B44E4E245F4A30E559BFC0D0739"
+ assertEquals(22.35, thresholdCheck.getNormalizedDeviceId().toDouble(), 0.01)
+
+ fakePreferenceService.deviceIdentifier = "07D85B44E4E245F4A30E559BFC0D07D9"
+ assertEquals(85.09, thresholdCheck.getNormalizedDeviceId().toDouble(), 0.01)
+ }
+
+ @Test
+ fun `test new normalized DeviceId`() {
+ fakePreferenceService.deviceIdentifier = "07D85B44E4E245F4A30E559BFC000000"
+ assertEquals(0.0, thresholdCheck.getNormalizedLargeDeviceId().toDouble(), 0.01)
+
+ fakePreferenceService.deviceIdentifier = "07D85B44E4E245F4A30E559BFCFFFFFF"
+ assertEquals(100.0, thresholdCheck.getNormalizedLargeDeviceId().toDouble(), 0.01)
+
+ fakePreferenceService.deviceIdentifier = "07D85B44E4E245F4A30E559BFC0D0739"
+ assertEquals(5.08, thresholdCheck.getNormalizedLargeDeviceId().toDouble(), 0.01)
+
+ fakePreferenceService.deviceIdentifier = "07D85B44E4E245F4A30E559BFCED0739"
+ assertEquals(92.58, thresholdCheck.getNormalizedLargeDeviceId().toDouble(), 0.01)
+ }
+
+ @Test
+ fun `test isBehaviourEnabled`() {
+ fakePreferenceService.deviceIdentifier = "07D85B44E4E245F4A30E559BFC000000"
+ assertFalse(thresholdCheck.isBehaviorEnabled(0.0f))
+ assertTrue(thresholdCheck.isBehaviorEnabled(0.1f))
+ assertTrue(thresholdCheck.isBehaviorEnabled(100.0f))
+ assertTrue(thresholdCheck.isBehaviorEnabled(99.9f))
+ assertTrue(thresholdCheck.isBehaviorEnabled(34.9f))
+
+ fakePreferenceService.deviceIdentifier = "07D85B44E4E245F4A30E559BFCFFFFFF"
+ assertFalse(thresholdCheck.isBehaviorEnabled(99.9f))
+ assertTrue(thresholdCheck.isBehaviorEnabled(100.0f))
+
+ fakePreferenceService.deviceIdentifier = "07D85B44E4E245F4A30E559BFC0D0739"
+ assertFalse(thresholdCheck.isBehaviorEnabled(0.0f))
+ assertFalse(thresholdCheck.isBehaviorEnabled(2.0f))
+ assertFalse(thresholdCheck.isBehaviorEnabled(5.0f))
+ assertFalse(thresholdCheck.isBehaviorEnabled(5.07f))
+ assertTrue(thresholdCheck.isBehaviorEnabled(5.09f))
+ assertTrue(thresholdCheck.isBehaviorEnabled(47.92f))
+ assertTrue(thresholdCheck.isBehaviorEnabled(100.0f))
+ }
+
+ @Test
+ fun `test isBehaviourEnabled with bad input`() {
+ fakePreferenceService.deviceIdentifier = "07D85B44E4E245F4A30E559BFCFFFFFF"
+ assertFalse(thresholdCheck.isBehaviorEnabled(1000f))
+ assertFalse(thresholdCheck.isBehaviorEnabled(-1000f))
+ }
+
+ @Test
+ fun `test app framework`() {
+ assertEquals(AppFramework.NATIVE, service.appFramework)
+ }
+
+ @Test(expected = IllegalArgumentException::class)
+ fun testEmptyAppId() {
+ createService(appId = null)
+ }
+
+ @Test(expected = IllegalArgumentException::class)
+ fun testNullAppId() {
+ createService(appId = null)
+ }
+
+ @Test
+ fun testNoAppIdRequiredWithExporters() {
+ val cfg = OpenTelemetryConfiguration(
+ SpanSinkImpl(),
+ LogSinkImpl(),
+ SystemInfo()
+ )
+ cfg.addLogExporter(FakeLogRecordExporter())
+ val service = createService(config = cfg, appId = null)
+ assertNotNull(service)
+ assertTrue(service.isOnlyUsingOtelExporters())
+ }
+
+ /**
+ * Create a new instance of the [ConfigServiceImpl] using the passed in [worker] to run
+ * tasks for its internal [BackgroundWorker]
+ */
+ private fun createService(
+ config: OpenTelemetryConfiguration = OpenTelemetryConfiguration(
+ SpanSinkImpl(),
+ LogSinkImpl(),
+ SystemInfo()
+ ),
+ appId: String? = "AbCdE",
+ ): ConfigServiceImpl {
+ thresholdCheck = BehaviorThresholdCheck { fakePreferenceService.deviceIdentifier }
+ return ConfigServiceImpl(
+ openTelemetryCfg = config,
+ preferencesService = fakePreferenceService,
+ suppliedFramework = AppFramework.NATIVE,
+ instrumentedConfig = FakeInstrumentedConfig(project = FakeProjectConfig(appId = appId)),
+ remoteConfig = remoteConfig,
+ thresholdCheck = thresholdCheck
+ )
+ }
+}
diff --git a/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/config/EmbraceConfigServiceTest.kt b/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/config/EmbraceConfigServiceTest.kt
deleted file mode 100644
index 2683920eb0..0000000000
--- a/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/config/EmbraceConfigServiceTest.kt
+++ /dev/null
@@ -1,346 +0,0 @@
-package io.embrace.android.embracesdk.internal.config
-
-import io.embrace.android.embracesdk.concurrency.BlockingScheduledExecutorService
-import io.embrace.android.embracesdk.fakes.FakeClock
-import io.embrace.android.embracesdk.fakes.FakeLogRecordExporter
-import io.embrace.android.embracesdk.fakes.FakePreferenceService
-import io.embrace.android.embracesdk.fakes.FakeProcessStateService
-import io.embrace.android.embracesdk.fakes.fakeBackgroundWorker
-import io.embrace.android.embracesdk.internal.SystemInfo
-import io.embrace.android.embracesdk.internal.comms.api.ApiService
-import io.embrace.android.embracesdk.internal.comms.api.CachedConfig
-import io.embrace.android.embracesdk.internal.comms.delivery.CacheService
-import io.embrace.android.embracesdk.internal.config.remote.AnrRemoteConfig
-import io.embrace.android.embracesdk.internal.config.remote.RemoteConfig
-import io.embrace.android.embracesdk.internal.logging.EmbLogger
-import io.embrace.android.embracesdk.internal.logging.EmbLoggerImpl
-import io.embrace.android.embracesdk.internal.logs.LogSinkImpl
-import io.embrace.android.embracesdk.internal.opentelemetry.OpenTelemetryConfiguration
-import io.embrace.android.embracesdk.internal.payload.AppFramework
-import io.embrace.android.embracesdk.internal.prefs.PreferencesService
-import io.embrace.android.embracesdk.internal.session.lifecycle.ProcessStateService
-import io.embrace.android.embracesdk.internal.spans.SpanSinkImpl
-import io.embrace.android.embracesdk.internal.worker.BackgroundWorker
-import io.mockk.clearAllMocks
-import io.mockk.every
-import io.mockk.mockk
-import io.mockk.mockkStatic
-import io.mockk.unmockkAll
-import org.junit.After
-import org.junit.AfterClass
-import org.junit.Assert.assertEquals
-import org.junit.Assert.assertFalse
-import org.junit.Assert.assertNotNull
-import org.junit.Assert.assertTrue
-import org.junit.Before
-import org.junit.BeforeClass
-import org.junit.Test
-
-internal class EmbraceConfigServiceTest {
-
- private lateinit var fakePreferenceService: PreferencesService
- private lateinit var service: EmbraceConfigService
- private lateinit var worker: BackgroundWorker
-
- companion object {
- private lateinit var remoteConfig: RemoteConfig
- private lateinit var mockApiService: ApiService
- private lateinit var processStateService: ProcessStateService
- private lateinit var mockCacheService: CacheService
- private lateinit var logger: EmbLogger
- private lateinit var fakeClock: FakeClock
- private lateinit var mockConfigListener: () -> Unit
- private lateinit var fakeCachedConfig: RemoteConfig
- private var configListenerTriggered = false
-
- /**
- * Setup before all tests get executed. Create mocks here.
- */
- @BeforeClass
- @JvmStatic
- fun setupBeforeAll() {
- mockkStatic(RemoteConfig::class)
- remoteConfig = RemoteConfig()
- mockApiService = mockk()
- processStateService = FakeProcessStateService()
- mockCacheService = mockk(relaxed = true)
- fakeClock = FakeClock()
- logger = EmbLoggerImpl()
- configListenerTriggered = false
- mockConfigListener = { configListenerTriggered = true }
- fakeCachedConfig = RemoteConfig( // alter config to trigger listener
- anrConfig = AnrRemoteConfig()
- )
- }
-
- /**
- * Setup after all tests get executed. Un-mock all here.
- */
- @AfterClass
- @JvmStatic
- fun tearDownAfterAll() {
- unmockkAll()
- }
- }
-
- /**
- * Setup before each test.
- */
- @Before
- fun setup() {
- fakeClock.setCurrentTime(1000000000000)
- every { mockApiService.getConfig() } returns remoteConfig
- fakePreferenceService = FakePreferenceService(deviceIdentifier = "07D85B44E4E245F4A30E559BFC0D07FF")
- every {
- mockCacheService.loadObject("config.json", RemoteConfig::class.java)
- } returns fakeCachedConfig
- every { mockApiService.getCachedConfig() } returns CachedConfig(fakeCachedConfig, null)
- worker = fakeBackgroundWorker()
- service = createService(worker = worker, action = {})
- assertFalse(service.isOnlyUsingOtelExporters())
- }
-
- /**
- * Setup after each test. Clean mocks content.
- */
- @After
- fun tearDown() {
- clearAllMocks()
- }
-
- @Suppress("DEPRECATION")
- @Test
- fun `test legacy normalized DeviceId`() {
- fakePreferenceService.deviceIdentifier = "07D85B44E4E245F4A30E559BFC0D0700"
- assertEquals(0.0, service.thresholdCheck.getNormalizedDeviceId().toDouble(), 0.01)
-
- fakePreferenceService.deviceIdentifier = "07D85B44E4E245F4A30E559BFC0D07FF"
- assertEquals(100.0, service.thresholdCheck.getNormalizedDeviceId().toDouble(), 0.01)
-
- fakePreferenceService.deviceIdentifier = "07D85B44E4E245F4A30E559BFC0D0739"
- assertEquals(22.35, service.thresholdCheck.getNormalizedDeviceId().toDouble(), 0.01)
-
- fakePreferenceService.deviceIdentifier = "07D85B44E4E245F4A30E559BFC0D07D9"
- assertEquals(85.09, service.thresholdCheck.getNormalizedDeviceId().toDouble(), 0.01)
- }
-
- @Test
- fun `test new normalized DeviceId`() {
- fakePreferenceService.deviceIdentifier = "07D85B44E4E245F4A30E559BFC000000"
- assertEquals(0.0, service.thresholdCheck.getNormalizedLargeDeviceId().toDouble(), 0.01)
-
- fakePreferenceService.deviceIdentifier = "07D85B44E4E245F4A30E559BFCFFFFFF"
- assertEquals(100.0, service.thresholdCheck.getNormalizedLargeDeviceId().toDouble(), 0.01)
-
- fakePreferenceService.deviceIdentifier = "07D85B44E4E245F4A30E559BFC0D0739"
- assertEquals(5.08, service.thresholdCheck.getNormalizedLargeDeviceId().toDouble(), 0.01)
-
- fakePreferenceService.deviceIdentifier = "07D85B44E4E245F4A30E559BFCED0739"
- assertEquals(92.58, service.thresholdCheck.getNormalizedLargeDeviceId().toDouble(), 0.01)
- }
-
- @Test
- fun `test isBehaviourEnabled`() {
- fakePreferenceService.deviceIdentifier = "07D85B44E4E245F4A30E559BFC000000"
- assertFalse(service.thresholdCheck.isBehaviorEnabled(0.0f))
- assertTrue(service.thresholdCheck.isBehaviorEnabled(0.1f))
- assertTrue(service.thresholdCheck.isBehaviorEnabled(100.0f))
- assertTrue(service.thresholdCheck.isBehaviorEnabled(99.9f))
- assertTrue(service.thresholdCheck.isBehaviorEnabled(34.9f))
-
- fakePreferenceService.deviceIdentifier = "07D85B44E4E245F4A30E559BFCFFFFFF"
- assertFalse(service.thresholdCheck.isBehaviorEnabled(99.9f))
- assertTrue(service.thresholdCheck.isBehaviorEnabled(100.0f))
-
- fakePreferenceService.deviceIdentifier = "07D85B44E4E245F4A30E559BFC0D0739"
- assertFalse(service.thresholdCheck.isBehaviorEnabled(0.0f))
- assertFalse(service.thresholdCheck.isBehaviorEnabled(2.0f))
- assertFalse(service.thresholdCheck.isBehaviorEnabled(5.0f))
- assertFalse(service.thresholdCheck.isBehaviorEnabled(5.07f))
- assertTrue(service.thresholdCheck.isBehaviorEnabled(5.09f))
- assertTrue(service.thresholdCheck.isBehaviorEnabled(47.92f))
- assertTrue(service.thresholdCheck.isBehaviorEnabled(100.0f))
- }
-
- @Test
- fun `test isBehaviourEnabled with bad input`() {
- fakePreferenceService.deviceIdentifier = "07D85B44E4E245F4A30E559BFCFFFFFF"
- assertFalse(service.thresholdCheck.isBehaviorEnabled(1000f))
- assertFalse(service.thresholdCheck.isBehaviorEnabled(-1000f))
- }
-
- @Test
- fun `test config exists in cache and is loaded correctly`() {
- assertTrue(service.anrBehavior.isAnrCaptureEnabled())
-
- val obj = RemoteConfig(anrConfig = AnrRemoteConfig(pctEnabled = 0))
- every { mockApiService.getCachedConfig() } returns CachedConfig(obj, null)
- service.loadConfigFromCache()
-
- // config was updated
- assertFalse(service.anrBehavior.isAnrCaptureEnabled())
- }
-
- @Test
- fun `test config does not exist in cache, so it's not loaded`() {
- assertTrue(service.anrBehavior.isAnrCaptureEnabled())
- every { mockApiService.getCachedConfig() } returns CachedConfig(null, null)
- service.loadConfigFromCache()
-
- // config was not updated
- assertTrue(service.anrBehavior.isAnrCaptureEnabled())
- }
-
- @Test
- fun `test service constructor reads cached config`() {
- val obj = RemoteConfig(anrConfig = AnrRemoteConfig(pctEnabled = 0))
- every { mockApiService.getConfig() } returns null
- every { mockApiService.getCachedConfig() } returns CachedConfig(obj, null)
- service = createService(worker)
-
- // config was updated
- assertFalse(service.anrBehavior.isAnrCaptureEnabled())
- }
-
- /**
- * Test that calling getConfig() notifies the listener.
- * As we are using a DirectExecutor this method will run synchronously and
- * return the updated config.
- * In a real situation, the async refresh would be triggered and the config returned would be the previous one.
- */
- @Test
- fun `test getConfig() notifies a listener`() {
- // advance the clock so it's safe to retry config refresh
- fakeClock.tick(1000000000000)
-
- // return a different object from default so listener triggers
- val newConfig = RemoteConfig(anrConfig = AnrRemoteConfig(sampleIntervalMs = 200))
- every { mockApiService.getConfig() } returns newConfig
- fakePreferenceService.sdkDisabled = false
- service.addListener(mockConfigListener)
-
- // call an arbitrary function to trigger a config refresh
- service.anrBehavior.isAnrCaptureEnabled()
- assertTrue(configListenerTriggered)
- }
-
- /**
- * Test that calling getConfig() refreshes the config and notify the listener
- * As we are using a DirectExecutor this method will run synchronously and
- * return the updated config.
- * In a real situation, the async refresh would be triggered and the config returned would be the previous one.
- */
- @Test
- fun `test onForeground() refreshes the config`() {
- // advance the clock so it's safe to retry config refresh
- fakeClock.tick(1000000000000)
- val newConfig = RemoteConfig(anrConfig = AnrRemoteConfig())
- every { mockApiService.getConfig() } returns newConfig
- fakePreferenceService.sdkDisabled = false
- service.addListener(mockConfigListener)
-
- service.onForeground(true, 1100L)
-
- assertTrue(configListenerTriggered)
- }
-
- @Test
- fun `test onForeground() with sdk started and config sdkDisabled=true stops the SDK`() {
- var stopped = false
- service = createService(worker, action = {
- stopped = true
- })
- fakePreferenceService.sdkDisabled = true
- service.onForeground(true, 1100L)
- assertTrue(stopped)
- }
-
- @Test
- fun `test isSdkDisabled returns true`() {
- fakePreferenceService.sdkDisabled = true
- assertTrue(service.isSdkDisabled())
- }
-
- @Test
- fun `test isSdkDisabled returns false`() {
- fakePreferenceService.sdkDisabled = false
- assertFalse(service.isSdkDisabled())
- }
-
- @Test
- fun `Update listeners when cached config is loaded`() {
- // Use ExecutorService that requires tasks to be explicitly run. This allows us to simulate the case
- // when the loading from the cache doesn't run before the config is read.
-
- val executorService = BlockingScheduledExecutorService(blockingMode = true)
-
- every { mockApiService.getCachedConfig() } returns CachedConfig(null, null)
-
- // Create a new instance of the ConfigService where the value of the config is what it is when the config
- // variable is initialized, before the cached version is loaded.
- val configService = createService(BackgroundWorker(executorService))
- assertFalse(configService.hasValidRemoteConfig())
-
- // call arbitrary function to trigger config refresh
- configService.anrBehavior.isAnrCaptureEnabled()
-
- // Only run the task from the executor that loads the cached config to the ConfigService so the call to fetch
- // a new config from the server isn't run
- executorService.runCurrentlyBlocked()
- assertTrue(configService.hasValidRemoteConfig())
- }
-
- @Test
- fun `test app framework`() {
- assertEquals(AppFramework.NATIVE, service.appFramework)
- }
-
- @Test(expected = IllegalArgumentException::class)
- fun testEmptyAppId() {
- createService(worker = worker, appId = null)
- }
-
- @Test(expected = IllegalArgumentException::class)
- fun testNullAppId() {
- createService(worker = worker, appId = null)
- }
-
- @Test
- fun testNoAppIdRequiredWithExporters() {
- val cfg = OpenTelemetryConfiguration(
- SpanSinkImpl(),
- LogSinkImpl(),
- SystemInfo()
- )
- cfg.addLogExporter(FakeLogRecordExporter())
- val service = createService(worker = worker, config = cfg, appId = null)
- assertNotNull(service)
- assertTrue(service.isOnlyUsingOtelExporters())
- }
-
- /**
- * Create a new instance of the [EmbraceConfigService] using the passed in [worker] to run
- * tasks for its internal [BackgroundWorker]
- */
- private fun createService(
- worker: BackgroundWorker,
- action: ConfigService.() -> Unit = {},
- config: OpenTelemetryConfiguration = OpenTelemetryConfiguration(
- SpanSinkImpl(),
- LogSinkImpl(),
- SystemInfo()
- ),
- appId: String? = "AbCdE",
- ): EmbraceConfigService = EmbraceConfigService(
- openTelemetryCfg = config,
- preferencesService = fakePreferenceService,
- clock = fakeClock,
- logger = logger,
- backgroundWorker = worker,
- suppliedFramework = AppFramework.NATIVE,
- foregroundAction = action,
- appIdFromConfig = appId
- ).apply {
- remoteConfigSource = mockApiService
- }
-}
diff --git a/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/config/OkHttpRemoteConfigSourceTest.kt b/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/config/OkHttpRemoteConfigSourceTest.kt
new file mode 100644
index 0000000000..a3f2868d2f
--- /dev/null
+++ b/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/config/OkHttpRemoteConfigSourceTest.kt
@@ -0,0 +1,181 @@
+package io.embrace.android.embracesdk.internal.config
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import io.embrace.android.embracesdk.fakes.TestPlatformSerializer
+import io.embrace.android.embracesdk.fakes.config.FakeBaseUrlConfig
+import io.embrace.android.embracesdk.fakes.config.FakeInstrumentedConfig
+import io.embrace.android.embracesdk.internal.comms.api.EmbraceApiUrlBuilder
+import io.embrace.android.embracesdk.internal.config.remote.BackgroundActivityRemoteConfig
+import io.embrace.android.embracesdk.internal.config.remote.RemoteConfig
+import io.embrace.android.embracesdk.internal.config.source.OkHttpRemoteConfigSource
+import okhttp3.OkHttpClient
+import okhttp3.Protocol
+import okhttp3.mockwebserver.MockResponse
+import okhttp3.mockwebserver.MockWebServer
+import okhttp3.mockwebserver.RecordedRequest
+import okio.Buffer
+import okio.GzipSink
+import okio.buffer
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertNull
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import java.util.concurrent.TimeUnit
+
+@RunWith(AndroidJUnit4::class)
+class OkHttpRemoteConfigSourceTest {
+
+ private lateinit var server: MockWebServer
+ private lateinit var client: OkHttpClient
+ private lateinit var urlBuilder: EmbraceApiUrlBuilder
+ private lateinit var source: OkHttpRemoteConfigSource
+
+ private val remoteConfig = RemoteConfig(
+ backgroundActivityConfig = BackgroundActivityRemoteConfig(100f)
+ )
+ private lateinit var configResponseBuffer: Buffer
+
+ @Before
+ fun setUp() {
+ server = MockWebServer().apply {
+ protocols = listOf(Protocol.HTTP_1_1, Protocol.HTTP_2)
+ start()
+ }
+ val baseUrl = server.url("api").toString()
+ client = OkHttpClient.Builder().build()
+ urlBuilder = EmbraceApiUrlBuilder(
+ "deviceId",
+ "1.0.0",
+ FakeInstrumentedConfig(
+ baseUrls = FakeBaseUrlConfig(
+ configImpl = baseUrl,
+ )
+ )
+ )
+
+ // serialize the config response
+ configResponseBuffer = Buffer()
+ val gzipSink = GzipSink(configResponseBuffer).buffer()
+ TestPlatformSerializer().toJson(
+ remoteConfig,
+ RemoteConfig::class.java,
+ gzipSink.outputStream()
+ )
+ source = OkHttpRemoteConfigSource(client, urlBuilder, TestPlatformSerializer())
+ }
+
+ @Test
+ fun `test config 2xx`() {
+ val (cfg, request) = executeRequest(
+ MockResponse().setResponseCode(200).setBody(configResponseBuffer)
+ )
+ assertConfigRequestReceived(request)
+ assertConfigResponseDeserialized(cfg)
+ }
+
+ @Test
+ fun `test config 4xx`() {
+ val (cfg, request) = executeRequest(
+ MockResponse().setResponseCode(400)
+ )
+ assertConfigRequestReceived(request)
+ assertConfigResponseNotDeserialized(cfg)
+ }
+
+ @Test
+ fun `test config 5xx`() {
+ val (cfg, request) = executeRequest(
+ MockResponse().setResponseCode(500)
+ )
+ assertConfigRequestReceived(request)
+ assertConfigResponseNotDeserialized(cfg)
+ }
+
+ @Test
+ fun `test no response from server`() {
+ client = client.newBuilder().callTimeout(1, TimeUnit.MILLISECONDS).build()
+ val (cfg, request) = executeRequest(null)
+ assertConfigRequestNotReceived(request)
+ assertConfigResponseNotDeserialized(cfg)
+ }
+
+ @Test
+ fun `test invalid response from server`() {
+ val (cfg, request) = executeRequest(
+ MockResponse().setResponseCode(200).setBody("{")
+ )
+ assertConfigRequestReceived(request)
+ assertConfigResponseNotDeserialized(cfg)
+ }
+
+ @Test
+ fun `test etag header respected`() {
+ val etagValue = "attempt_1"
+ val (cfg, request) = executeRequest(
+ MockResponse().setResponseCode(200)
+ .setBody(configResponseBuffer)
+ .setHeader("etag", etagValue)
+ )
+ assertConfigRequestReceived(request)
+ assertNull(request?.getHeader("If-None-Match"))
+ assertConfigResponseDeserialized(cfg)
+
+ // second request with etag
+ val (secondCfg, secondRequest) = executeRequest(
+ MockResponse().setResponseCode(304)
+ .setHeader("etag", etagValue)
+ )
+ assertConfigRequestReceived(secondRequest)
+ assertEquals(etagValue, secondRequest?.getHeader("If-None-Match"))
+ assertConfigResponseNotDeserialized(secondCfg)
+ }
+
+ private fun executeRequest(response: MockResponse?): Pair {
+ if (response == null) {
+ return Pair(null, null)
+ }
+ server.enqueue(response)
+ val cfg = source.getConfig()?.cfg
+ val request = pollRequest()
+ CallData(request, cfg)
+ return Pair(cfg, request)
+ }
+
+ private fun assertEmbraceHeadersAdded(request: RecordedRequest?) {
+ val headers = request?.headers?.toMap() ?: error("Request headers cannot be null")
+ assertEquals("application/json", headers["Accept"])
+ assertEquals("application/json", headers["Content-Type"])
+ assertEquals("gzip", headers["Accept-Encoding"])
+ assertEquals("abcde", headers["X-EM-AID"])
+ assertEquals("deviceId", headers["X-EM-DID"])
+ }
+
+ private fun assertConfigRequestNotReceived(request: RecordedRequest?) {
+ assertNull(request)
+ }
+
+ private fun assertConfigRequestReceived(request: RecordedRequest?) {
+ checkNotNull(request)
+ assertEmbraceHeadersAdded(request)
+ val requestUrl = request.requestUrl?.toUrl() ?: error("Request URL cannot be null")
+ assertEquals("/api/v2/config", requestUrl.path)
+ assertEquals("appId=abcde&osVersion=21.0.0&appVersion=1.0.0&deviceId=deviceId", requestUrl.query)
+ }
+
+ private fun assertConfigResponseDeserialized(cfg: RemoteConfig?) {
+ checkNotNull(cfg)
+ assertEquals(remoteConfig.backgroundActivityConfig, cfg.backgroundActivityConfig)
+ }
+
+ private fun assertConfigResponseNotDeserialized(cfg: RemoteConfig?) {
+ assertNull(cfg)
+ }
+
+ private data class CallData(
+ val request: RecordedRequest?,
+ val deserializedConfig: RemoteConfig?,
+ )
+
+ private fun pollRequest(): RecordedRequest? = server.takeRequest(1, TimeUnit.SECONDS)
+}
diff --git a/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/config/behavior/AnrBehaviorImplTest.kt b/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/config/behavior/AnrBehaviorImplTest.kt
index 14d9a46d71..aa73c8d73f 100644
--- a/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/config/behavior/AnrBehaviorImplTest.kt
+++ b/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/config/behavior/AnrBehaviorImplTest.kt
@@ -3,6 +3,7 @@ package io.embrace.android.embracesdk.internal.config.behavior
import io.embrace.android.embracesdk.fakes.createAnrBehavior
import io.embrace.android.embracesdk.internal.config.remote.AllowedNdkSampleMethod
import io.embrace.android.embracesdk.internal.config.remote.AnrRemoteConfig
+import io.embrace.android.embracesdk.internal.config.remote.RemoteConfig
import io.embrace.android.embracesdk.internal.config.remote.Unwinder
import org.junit.Assert.assertEquals
import org.junit.Assert.assertFalse
@@ -57,7 +58,7 @@ internal class AnrBehaviorImplTest {
@Test
fun testRemoteAndLocal() {
- with(createAnrBehavior(remoteCfg = { remote })) {
+ with(createAnrBehavior(remoteCfg = RemoteConfig(anrConfig = remote))) {
assertEquals(200L, getSamplingIntervalMs())
assertFalse(isNativeThreadAnrSamplingOffsetEnabled())
assertFalse(isNativeThreadAnrSamplingAllowlistIgnored())
diff --git a/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/config/behavior/AppExitInfoBehaviorImplTest.kt b/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/config/behavior/AppExitInfoBehaviorImplTest.kt
index 6bf0c3b282..a14cdd2810 100644
--- a/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/config/behavior/AppExitInfoBehaviorImplTest.kt
+++ b/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/config/behavior/AppExitInfoBehaviorImplTest.kt
@@ -23,7 +23,7 @@ internal class AppExitInfoBehaviorImplTest {
@Test
fun testLocalAndRemote() {
- with(createAppExitInfoBehavior(remoteCfg = { remote })) {
+ with(createAppExitInfoBehavior(remoteCfg = remote)) {
assertEquals(55209, getTraceMaxLimit())
assertTrue(isAeiCaptureEnabled())
}
diff --git a/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/config/behavior/AutoDataCaptureBehaviorImplTest.kt b/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/config/behavior/AutoDataCaptureBehaviorImplTest.kt
index 314567bd9c..60159ac88a 100644
--- a/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/config/behavior/AutoDataCaptureBehaviorImplTest.kt
+++ b/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/config/behavior/AutoDataCaptureBehaviorImplTest.kt
@@ -40,7 +40,7 @@ internal class AutoDataCaptureBehaviorImplTest {
@Test
fun testLocalAndRemote() {
- with(createAutoDataCaptureBehavior(remoteCfg = { remote })) {
+ with(createAutoDataCaptureBehavior(remoteCfg = remote)) {
assertFalse(is3rdPartySigHandlerDetectionEnabled())
assertFalse(isComposeClickCaptureEnabled())
assertFalse(isThermalStatusCaptureEnabled())
@@ -56,7 +56,7 @@ internal class AutoDataCaptureBehaviorImplTest {
}
// Jetpack Compose disabled remotely
- with(createAutoDataCaptureBehavior(remoteCfg = { remote })) {
+ with(createAutoDataCaptureBehavior(remoteCfg = remote)) {
assertFalse(isComposeClickCaptureEnabled())
}
val remoteComposeKillSwitchOff = RemoteConfig(
@@ -69,7 +69,7 @@ internal class AutoDataCaptureBehaviorImplTest {
// Jetpack Compose enabled remotely
with(
createAutoDataCaptureBehavior(
- remoteCfg = { remoteComposeKillSwitchOff }
+ remoteCfg = remoteComposeKillSwitchOff
)
) {
assertTrue(isComposeClickCaptureEnabled())
diff --git a/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/config/behavior/BackgroundActivityBehaviorImplTest.kt b/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/config/behavior/BackgroundActivityBehaviorImplTest.kt
index 5e7e84fd16..2bb34475f7 100644
--- a/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/config/behavior/BackgroundActivityBehaviorImplTest.kt
+++ b/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/config/behavior/BackgroundActivityBehaviorImplTest.kt
@@ -2,6 +2,7 @@ package io.embrace.android.embracesdk.internal.config.behavior
import io.embrace.android.embracesdk.fakes.createBackgroundActivityBehavior
import io.embrace.android.embracesdk.internal.config.remote.BackgroundActivityRemoteConfig
+import io.embrace.android.embracesdk.internal.config.remote.RemoteConfig
import org.junit.Assert.assertEquals
import org.junit.Assert.assertFalse
import org.junit.Test
@@ -24,7 +25,7 @@ internal class BackgroundActivityBehaviorImplTest {
@Test
fun testRemoteAndLocal() {
- with(createBackgroundActivityBehavior(remoteCfg = { remote })) {
+ with(createBackgroundActivityBehavior(remoteCfg = RemoteConfig(backgroundActivityConfig = remote))) {
assertFalse(isBackgroundActivityCaptureEnabled())
assertEquals(100, getManualBackgroundActivityLimit())
assertEquals(5000L, getMinBackgroundActivityDuration())
diff --git a/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/config/behavior/BreadcrumbBehaviorImplTest.kt b/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/config/behavior/BreadcrumbBehaviorImplTest.kt
index ea66b8b759..3393d857b2 100644
--- a/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/config/behavior/BreadcrumbBehaviorImplTest.kt
+++ b/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/config/behavior/BreadcrumbBehaviorImplTest.kt
@@ -1,8 +1,8 @@
package io.embrace.android.embracesdk.internal.config.behavior
+import io.embrace.android.embracesdk.internal.config.instrumented.InstrumentedConfigImpl
import io.embrace.android.embracesdk.internal.config.remote.RemoteConfig
import io.embrace.android.embracesdk.internal.config.remote.UiRemoteConfig
-import io.embrace.android.embracesdk.internal.utils.Uuid
import org.junit.Assert.assertEquals
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
@@ -19,11 +19,14 @@ internal class BreadcrumbBehaviorImplTest {
)
)
- private val behaviorThresholdCheck = BehaviorThresholdCheck { Uuid.getEmbUuid() }
-
@Test
fun testDefaults() {
- with(BreadcrumbBehaviorImpl(thresholdCheck = behaviorThresholdCheck) { null }) {
+ with(
+ BreadcrumbBehaviorImpl(
+ InstrumentedConfigImpl,
+ null,
+ )
+ ) {
assertEquals(100, getCustomBreadcrumbLimit())
assertEquals(100, getTapBreadcrumbLimit())
assertEquals(100, getWebViewBreadcrumbLimit())
@@ -39,7 +42,10 @@ internal class BreadcrumbBehaviorImplTest {
@Test
fun testRemoteAndLocal() {
with(
- BreadcrumbBehaviorImpl(thresholdCheck = behaviorThresholdCheck) { remote }
+ BreadcrumbBehaviorImpl(
+ InstrumentedConfigImpl,
+ remote,
+ )
) {
assertEquals(99, getCustomBreadcrumbLimit())
assertEquals(98, getTapBreadcrumbLimit())
diff --git a/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/config/behavior/DataCaptureEventBehaviorImplTest.kt b/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/config/behavior/DataCaptureEventBehaviorImplTest.kt
index 81e61c6824..18171aadee 100644
--- a/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/config/behavior/DataCaptureEventBehaviorImplTest.kt
+++ b/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/config/behavior/DataCaptureEventBehaviorImplTest.kt
@@ -26,7 +26,7 @@ internal class DataCaptureEventBehaviorImplTest {
@Test
fun testRemoteOnly() {
- with(createDataCaptureEventBehavior(remoteCfg = { remote })) {
+ with(createDataCaptureEventBehavior(remoteCfg = remote)) {
assertFalse(isInternalExceptionCaptureEnabled())
assertFalse(isEventEnabled("my_event"))
assertTrue(isEventEnabled("other_event"))
diff --git a/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/config/behavior/LogMessageBehaviorImplTest.kt b/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/config/behavior/LogMessageBehaviorImplTest.kt
index a3b1f5967f..c73c0b553b 100644
--- a/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/config/behavior/LogMessageBehaviorImplTest.kt
+++ b/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/config/behavior/LogMessageBehaviorImplTest.kt
@@ -2,16 +2,19 @@ package io.embrace.android.embracesdk.internal.config.behavior
import io.embrace.android.embracesdk.fakes.createLogMessageBehavior
import io.embrace.android.embracesdk.internal.config.remote.LogRemoteConfig
+import io.embrace.android.embracesdk.internal.config.remote.RemoteConfig
import org.junit.Assert.assertEquals
import org.junit.Test
internal class LogMessageBehaviorImplTest {
- private val remote = LogRemoteConfig(
- 256,
- 200,
- 300,
- 400
+ private val remote = RemoteConfig(
+ logConfig = LogRemoteConfig(
+ 256,
+ 200,
+ 300,
+ 400
+ )
)
@Test
@@ -26,7 +29,7 @@ internal class LogMessageBehaviorImplTest {
@Test
fun testRemoteAndLocal() {
- with(createLogMessageBehavior(remoteCfg = { remote })) {
+ with(createLogMessageBehavior(remoteCfg = remote)) {
assertEquals(256, getLogMessageMaximumAllowedLength())
assertEquals(200, getInfoLogLimit())
assertEquals(300, getWarnLogLimit())
diff --git a/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/config/behavior/NetworkBehaviorImplTest.kt b/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/config/behavior/NetworkBehaviorImplTest.kt
index 0671dbc969..1d782f5781 100644
--- a/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/config/behavior/NetworkBehaviorImplTest.kt
+++ b/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/config/behavior/NetworkBehaviorImplTest.kt
@@ -32,7 +32,7 @@ internal class NetworkBehaviorImplTest {
@Test
fun testDefaults() {
- with(createNetworkBehavior(remoteCfg = { null })) {
+ with(createNetworkBehavior(remoteCfg = null)) {
assertFalse(isRequestContentLengthCaptureEnabled())
assertTrue(isHttpUrlConnectionCaptureEnabled())
assertEquals(1000, getRequestLimitPerDomain())
@@ -46,7 +46,7 @@ internal class NetworkBehaviorImplTest {
@Test
fun testRemoteOnly() {
- with(createNetworkBehavior(remoteCfg = { remote })) {
+ with(createNetworkBehavior(remoteCfg = remote)) {
assertEquals(409, getRequestLimitPerDomain())
assertEquals(mapOf("google.com" to 50), getLimitsByDomain())
assertTrue(isUrlEnabled("google.com"))
diff --git a/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/config/behavior/NetworkSpanForwardingBehaviorImplTest.kt b/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/config/behavior/NetworkSpanForwardingBehaviorImplTest.kt
index 5f63257132..19cc45a929 100644
--- a/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/config/behavior/NetworkSpanForwardingBehaviorImplTest.kt
+++ b/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/config/behavior/NetworkSpanForwardingBehaviorImplTest.kt
@@ -2,6 +2,7 @@ package io.embrace.android.embracesdk.internal.config.behavior
import io.embrace.android.embracesdk.fakes.createNetworkSpanForwardingBehavior
import io.embrace.android.embracesdk.internal.config.remote.NetworkSpanForwardingRemoteConfig
+import io.embrace.android.embracesdk.internal.config.remote.RemoteConfig
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
import org.junit.Test
@@ -17,17 +18,19 @@ internal class NetworkSpanForwardingBehaviorImplTest {
@Test
fun testRemote() {
- with(createNetworkSpanForwardingBehavior(remoteConfig = { remoteEnabled })) {
+ with(createNetworkSpanForwardingBehavior(remoteConfig = remoteEnabled)) {
assertTrue(isNetworkSpanForwardingEnabled())
}
- with(createNetworkSpanForwardingBehavior(remoteConfig = { remoteDisabled })) {
+ with(createNetworkSpanForwardingBehavior(remoteConfig = remoteDisabled)) {
assertFalse(isNetworkSpanForwardingEnabled())
}
}
companion object {
- private val remoteEnabled = NetworkSpanForwardingRemoteConfig(pctEnabled = 100.0f)
- private val remoteDisabled = NetworkSpanForwardingRemoteConfig(pctEnabled = 0.0f)
+ private val remoteEnabled =
+ RemoteConfig(networkSpanForwardingRemoteConfig = NetworkSpanForwardingRemoteConfig(pctEnabled = 100.0f))
+ private val remoteDisabled =
+ RemoteConfig(networkSpanForwardingRemoteConfig = NetworkSpanForwardingRemoteConfig(pctEnabled = 0.0f))
}
}
diff --git a/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/config/behavior/SdkEndpointBehaviorImplTest.kt b/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/config/behavior/SdkEndpointBehaviorImplTest.kt
deleted file mode 100644
index 2c042fbe42..0000000000
--- a/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/config/behavior/SdkEndpointBehaviorImplTest.kt
+++ /dev/null
@@ -1,16 +0,0 @@
-package io.embrace.android.embracesdk.internal.config.behavior
-
-import io.embrace.android.embracesdk.fakes.createSdkEndpointBehavior
-import org.junit.Assert.assertEquals
-import org.junit.Test
-
-internal class SdkEndpointBehaviorImplTest {
-
- @Test
- fun testDefaults() {
- with(createSdkEndpointBehavior()) {
- assertEquals("https://a-12345.config.emb-api.com", getConfig("12345"))
- assertEquals("https://a-12345.data.emb-api.com", getData("12345"))
- }
- }
-}
diff --git a/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/config/behavior/SdkModeBehaviorImplTest.kt b/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/config/behavior/SdkModeBehaviorImplTest.kt
index d7bcb0334e..062185e885 100644
--- a/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/config/behavior/SdkModeBehaviorImplTest.kt
+++ b/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/config/behavior/SdkModeBehaviorImplTest.kt
@@ -33,28 +33,28 @@ internal class SdkModeBehaviorImplTest {
// SDK disabled
var behavior = createSdkModeBehavior(
thresholdCheck = enabled,
- remoteCfg = { RemoteConfig(threshold = 0) }
+ remoteCfg = RemoteConfig(threshold = 0)
)
assertTrue(behavior.isSdkDisabled())
// SDK enabled
behavior = createSdkModeBehavior(
thresholdCheck = enabled,
- remoteCfg = { RemoteConfig(threshold = 100) }
+ remoteCfg = RemoteConfig(threshold = 100)
)
assertFalse(behavior.isSdkDisabled())
// SDK 30% enabled with default offset
behavior = createSdkModeBehavior(
thresholdCheck = halfEnabled,
- remoteCfg = { RemoteConfig(threshold = 30) }
+ remoteCfg = RemoteConfig(threshold = 30)
)
assertTrue(behavior.isSdkDisabled())
// SDK 30% enabled with non-default offset
behavior = createSdkModeBehavior(
thresholdCheck = halfEnabled,
- remoteCfg = { RemoteConfig(threshold = 30, offset = 25) }
+ remoteCfg = RemoteConfig(threshold = 30, offset = 25)
)
assertFalse(behavior.isSdkDisabled())
}
diff --git a/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/config/behavior/SensitiveKeysBehaviorImplTest.kt b/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/config/behavior/SensitiveKeysBehaviorImplTest.kt
index a13a0aeca5..c09d239c93 100644
--- a/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/config/behavior/SensitiveKeysBehaviorImplTest.kt
+++ b/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/config/behavior/SensitiveKeysBehaviorImplTest.kt
@@ -1,5 +1,8 @@
package io.embrace.android.embracesdk.internal.config.behavior
+import io.embrace.android.embracesdk.fakes.config.FakeInstrumentedConfig
+import io.embrace.android.embracesdk.fakes.config.FakeRedactionConfig
+import io.embrace.android.embracesdk.internal.config.instrumented.schema.InstrumentedConfig
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
import org.junit.Test
@@ -9,7 +12,7 @@ internal class SensitiveKeysBehaviorImplTest {
@Test
fun `keys are not sensitive if they are not in the sensitive keys list`() {
// given an empty sensitive list
- val behavior = SensitiveKeysBehaviorImpl(emptyList())
+ val behavior = SensitiveKeysBehaviorImpl(emptyList().toConfig())
// when checking if a key is sensitive
val isSensitive = behavior.isSensitiveKey("password")
@@ -21,7 +24,8 @@ internal class SensitiveKeysBehaviorImplTest {
@Test
fun `keys are not sensitive with a null sensitive keys list`() {
// given a null sensitive list
- val behavior = SensitiveKeysBehaviorImpl(null)
+ val behavior =
+ SensitiveKeysBehaviorImpl(FakeInstrumentedConfig(redaction = FakeRedactionConfig(sensitiveKeys = null)))
// when checking if a key is sensitive
val isSensitive = behavior.isSensitiveKey("password")
@@ -33,7 +37,7 @@ internal class SensitiveKeysBehaviorImplTest {
@Test
fun `keys are sensitive when found in the sensitive keys list`() {
// given a sensitive list with a key
- val behavior = SensitiveKeysBehaviorImpl(listOf("password"))
+ val behavior = SensitiveKeysBehaviorImpl(listOf("password").toConfig())
// when checking if a key present in the list is sensitive
val isSensitive = behavior.isSensitiveKey("password")
@@ -45,7 +49,7 @@ internal class SensitiveKeysBehaviorImplTest {
@Test
fun `keys in the sensitive list are truncated to 128 characters`() {
// given a sensitive list with a long key
- val behavior = SensitiveKeysBehaviorImpl(listOf("a".repeat(200)))
+ val behavior = SensitiveKeysBehaviorImpl(listOf("a".repeat(200)).toConfig())
// when checking if a key present in the list is sensitive
val sensitiveKey = behavior.isSensitiveKey("a".repeat(128))
@@ -60,7 +64,7 @@ internal class SensitiveKeysBehaviorImplTest {
fun `sensitive list is truncated to 10000 keys`() {
// given a sensitive list with more than 10000 keys
val behavior = SensitiveKeysBehaviorImpl(
- List(10000) { it.toString() } + "password"
+ (List(10000) { it.toString() } + "password").toConfig()
)
// when checking a key present in the 10001st position
@@ -74,10 +78,7 @@ internal class SensitiveKeysBehaviorImplTest {
fun `sensitive list with multiple keys`() {
// given a sensitive list with multiple keys
val behavior = SensitiveKeysBehaviorImpl(
- listOf(
- "password",
- "passkey"
- )
+ listOf("password", "passkey").toConfig(),
)
// when checking if a key present in the list is sensitive
@@ -90,4 +91,8 @@ internal class SensitiveKeysBehaviorImplTest {
assertTrue(anotherSensitiveKey)
assertFalse(notSensitiveKey)
}
+
+ private fun List.toConfig(): InstrumentedConfig {
+ return FakeInstrumentedConfig(redaction = FakeRedactionConfig(sensitiveKeys = this))
+ }
}
diff --git a/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/config/behavior/SessionBehaviorImplImplTest.kt b/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/config/behavior/SessionBehaviorImplImplTest.kt
index 94a15b97c7..05746fd16b 100644
--- a/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/config/behavior/SessionBehaviorImplImplTest.kt
+++ b/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/config/behavior/SessionBehaviorImplImplTest.kt
@@ -33,7 +33,7 @@ internal class SessionBehaviorImplImplTest {
@Test
fun testRemoteAndLocal() {
- with(createSessionBehavior(remoteCfg = { remote })) {
+ with(createSessionBehavior(remoteCfg = remote)) {
assertTrue(isGatingFeatureEnabled())
assertTrue(isSessionControlEnabled())
assertEquals(setOf("test"), getSessionComponents())
@@ -45,9 +45,7 @@ internal class SessionBehaviorImplImplTest {
@Test
fun `test upper case full session events`() {
val behavior = createSessionBehavior(
- remoteCfg = {
- buildGatingConfig(setOf("CRASHES", "ERRORS"))
- }
+ remoteCfg = buildGatingConfig(setOf("CRASHES", "ERRORS"))
)
assertEquals(setOf("crashes", "errors"), behavior.getFullSessionEvents())
}
@@ -55,9 +53,7 @@ internal class SessionBehaviorImplImplTest {
@Test
fun `test lower case full session events`() {
val behavior = createSessionBehavior(
- remoteCfg = {
- buildGatingConfig(setOf("crashes", "errors"))
- }
+ remoteCfg = buildGatingConfig(setOf("crashes", "errors"))
)
assertEquals(setOf("crashes", "errors"), behavior.getFullSessionEvents())
}
diff --git a/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/config/behavior/WebVitalsBehaviorTest.kt b/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/config/behavior/WebVitalsBehaviorTest.kt
index cdc92c2b14..fe39ba9c4f 100644
--- a/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/config/behavior/WebVitalsBehaviorTest.kt
+++ b/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/config/behavior/WebVitalsBehaviorTest.kt
@@ -22,7 +22,7 @@ internal class WebVitalsBehaviorTest {
@Test
fun testRemote() {
- with(createWebViewVitalsBehavior(remoteCfg = { remote })) {
+ with(createWebViewVitalsBehavior(remoteCfg = remote)) {
assertEquals(100, getMaxWebViewVitals())
assertFalse(isWebViewVitalsEnabled())
}
diff --git a/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/config/source/CombinedRemoteConfigSourceTest.kt b/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/config/source/CombinedRemoteConfigSourceTest.kt
new file mode 100644
index 0000000000..c3de00ac7d
--- /dev/null
+++ b/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/config/source/CombinedRemoteConfigSourceTest.kt
@@ -0,0 +1,69 @@
+package io.embrace.android.embracesdk.internal.config.source
+
+import io.embrace.android.embracesdk.concurrency.BlockingScheduledExecutorService
+import io.embrace.android.embracesdk.fakes.FakeRemoteConfigSource
+import io.embrace.android.embracesdk.fakes.FakeRemoteConfigStore
+import io.embrace.android.embracesdk.internal.config.remote.RemoteConfig
+import io.embrace.android.embracesdk.internal.worker.BackgroundWorker
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertNull
+import org.junit.Before
+import org.junit.Test
+
+class CombinedRemoteConfigSourceTest {
+
+ private lateinit var source: CombinedRemoteConfigSource
+ private lateinit var remoteConfig: RemoteConfig
+ private lateinit var executorService: BlockingScheduledExecutorService
+ private lateinit var remoteConfigSource: FakeRemoteConfigSource
+ private lateinit var remoteConfigStore: FakeRemoteConfigStore
+
+ @Before
+ fun setUp() {
+ remoteConfig = RemoteConfig(92)
+ executorService = BlockingScheduledExecutorService()
+ remoteConfigSource = FakeRemoteConfigSource(ConfigHttpResponse(remoteConfig, "another"))
+ remoteConfigStore = FakeRemoteConfigStore()
+ source = CombinedRemoteConfigSource(
+ remoteConfigStore,
+ lazy { remoteConfigSource },
+ BackgroundWorker(executorService)
+ )
+ }
+
+ @Test
+ fun `test initial config null`() {
+ assertNull(source.getConfig())
+ }
+
+ @Test
+ fun `test initial config populated`() {
+ val cfg = RemoteConfig(100)
+ source = CombinedRemoteConfigSource(
+ FakeRemoteConfigStore(ConfigHttpResponse(cfg, null)),
+ lazy { remoteConfigSource },
+ BackgroundWorker(executorService)
+ )
+ assertEquals(cfg, source.getConfig())
+ }
+
+ @Test
+ fun `test requests scheduled`() {
+ assertEquals(0, remoteConfigSource.callCount)
+ source.scheduleConfigRequests()
+ executorService.runCurrentlyBlocked()
+ assertEquals(1, remoteConfigSource.callCount)
+ assertNull(remoteConfigSource.etag)
+ }
+
+ @Test
+ fun `test persisted etag value populated`() {
+ remoteConfigStore.impl = ConfigHttpResponse(RemoteConfig(), "etag")
+ assertEquals(0, remoteConfigSource.callCount)
+ source.scheduleConfigRequests()
+ assertEquals("etag", remoteConfigSource.etag)
+ executorService.runCurrentlyBlocked()
+ assertEquals(1, remoteConfigSource.callCount)
+ assertEquals(1, remoteConfigStore.saveCount)
+ }
+}
diff --git a/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/config/store/RemoteConfigStoreImplTest.kt b/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/config/store/RemoteConfigStoreImplTest.kt
new file mode 100644
index 0000000000..6cd61be8df
--- /dev/null
+++ b/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/config/store/RemoteConfigStoreImplTest.kt
@@ -0,0 +1,48 @@
+package io.embrace.android.embracesdk.internal.config.store
+
+import io.embrace.android.embracesdk.fakes.TestPlatformSerializer
+import io.embrace.android.embracesdk.internal.config.remote.RemoteConfig
+import io.embrace.android.embracesdk.internal.config.source.ConfigHttpResponse
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertNull
+import org.junit.Before
+import org.junit.Test
+import java.io.File
+import java.nio.file.Files
+
+internal class RemoteConfigStoreImplTest {
+
+ private lateinit var store: RemoteConfigStoreImpl
+ private lateinit var dir: File
+
+ @Before
+ fun setUp() {
+ dir = Files.createTempDirectory("test").toFile()
+ store = RemoteConfigStoreImpl(TestPlatformSerializer(), dir)
+ }
+
+ @Test
+ fun `test config store`() {
+ assertNull(store.loadResponse())
+
+ // store a config
+ val config = RemoteConfig(50)
+ store.saveResponse(ConfigHttpResponse(config, "etag"))
+
+ // load the config
+ val loaded = checkNotNull(store.loadResponse())
+ assertEquals(config, loaded.cfg)
+ assertEquals("etag", loaded.etag)
+
+ val newConfig = RemoteConfig(100)
+ store.saveResponse(ConfigHttpResponse(newConfig, "another"))
+
+ val newLoaded = checkNotNull(store.loadResponse())
+ assertEquals(newConfig, newLoaded.cfg)
+ assertEquals("another", newLoaded.etag)
+
+ store.saveResponse(ConfigHttpResponse(newConfig, "another"))
+ assertEquals(newConfig, newLoaded.cfg)
+ assertEquals("another", newLoaded.etag)
+ }
+}
diff --git a/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/event/gating/EmbraceGatingServiceV2PayloadTest.kt b/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/event/gating/EmbraceGatingServiceV2PayloadTest.kt
index cd04ae0a30..e9b75af7da 100644
--- a/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/event/gating/EmbraceGatingServiceV2PayloadTest.kt
+++ b/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/event/gating/EmbraceGatingServiceV2PayloadTest.kt
@@ -32,8 +32,8 @@ internal class EmbraceGatingServiceV2PayloadTest {
@Before
fun setUp() {
- sessionBehavior = createSessionBehavior { cfg }
- configService = FakeConfigService(sessionBehavior = createSessionBehavior { cfg })
+ sessionBehavior = createSessionBehavior(cfg)
+ configService = FakeConfigService(sessionBehavior = createSessionBehavior(cfg))
logService = FakeLogService()
gatingService = EmbraceGatingService(configService, logService)
}
diff --git a/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/injection/AndroidServicesModuleImplTest.kt b/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/injection/AndroidServicesModuleImplTest.kt
index 65e40ff366..9024062d3d 100644
--- a/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/injection/AndroidServicesModuleImplTest.kt
+++ b/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/injection/AndroidServicesModuleImplTest.kt
@@ -1,20 +1,22 @@
package io.embrace.android.embracesdk.internal.injection
+import androidx.test.ext.junit.runners.AndroidJUnit4
import io.embrace.android.embracesdk.internal.prefs.EmbracePreferencesService
import io.mockk.mockk
import org.junit.Assert.assertTrue
import org.junit.Test
+import org.junit.runner.RunWith
+@RunWith(AndroidJUnit4::class)
internal class AndroidServicesModuleImplTest {
@Test
fun testDefault() {
val initModule = InitModuleImpl()
- val coreModule = createCoreModule(mockk(relaxed = true))
+ val coreModule = createCoreModule(mockk(relaxed = true), initModule)
val module = AndroidServicesModuleImpl(
initModule = initModule,
- coreModule = coreModule,
- workerThreadModule = WorkerThreadModuleImpl()
+ coreModule = coreModule
)
assertTrue(module.preferencesService is EmbracePreferencesService)
diff --git a/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/injection/ConfigModuleImplTest.kt b/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/injection/ConfigModuleImplTest.kt
index 853704db39..241b342706 100644
--- a/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/injection/ConfigModuleImplTest.kt
+++ b/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/injection/ConfigModuleImplTest.kt
@@ -1,14 +1,13 @@
package io.embrace.android.embracesdk.internal.injection
+import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
-import io.embrace.android.embracesdk.fakes.FakeConfigService
import io.embrace.android.embracesdk.fakes.FakeOpenTelemetryModule
import io.embrace.android.embracesdk.fakes.injection.FakeAndroidServicesModule
import io.embrace.android.embracesdk.fakes.injection.FakeInitModule
import io.embrace.android.embracesdk.fakes.injection.FakeWorkerThreadModule
import io.embrace.android.embracesdk.internal.payload.AppFramework
import org.junit.Assert.assertNotNull
-import org.junit.Assert.assertSame
import org.junit.Test
import org.junit.runner.RunWith
@@ -17,47 +16,16 @@ internal class ConfigModuleImplTest {
@Test
fun `test defaults`() {
+ val initModule = FakeInitModule()
val module = ConfigModuleImpl(
- initModule = FakeInitModule(),
+ initModule = initModule,
+ coreModule = createCoreModule(ApplicationProvider.getApplicationContext(), initModule),
openTelemetryModule = FakeOpenTelemetryModule(),
workerThreadModule = FakeWorkerThreadModule(),
androidServicesModule = FakeAndroidServicesModule(),
framework = AppFramework.NATIVE,
- configServiceProvider = { null },
- foregroundAction = {},
- appIdFromConfig = "AbCeD",
)
assertNotNull(module.configService)
- }
-
- @Test
- fun testConfigServiceProvider() {
- val fakeConfigService = FakeConfigService()
- val module = ConfigModuleImpl(
- initModule = FakeInitModule(),
- openTelemetryModule = FakeOpenTelemetryModule(),
- workerThreadModule = FakeWorkerThreadModule(),
- androidServicesModule = FakeAndroidServicesModule(),
- framework = AppFramework.NATIVE,
- configServiceProvider = { fakeConfigService },
- foregroundAction = {},
- appIdFromConfig = "AbCeD",
- )
- assertSame(fakeConfigService, module.configService)
- }
-
- @Test
- fun `validate appId in appIdProvider is used`() {
- val module = ConfigModuleImpl(
- initModule = FakeInitModule(),
- openTelemetryModule = FakeOpenTelemetryModule(),
- workerThreadModule = FakeWorkerThreadModule(),
- androidServicesModule = FakeAndroidServicesModule(),
- framework = AppFramework.NATIVE,
- configServiceProvider = { null },
- foregroundAction = {},
- appIdFromConfig = "AbCeD",
- )
- assertSame("AbCeD", module.configService.appId)
+ assertNotNull(module.urlBuilder)
}
}
diff --git a/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/injection/CoreModuleImplTest.kt b/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/injection/CoreModuleImplTest.kt
index eff0148d5a..bae0e15a31 100644
--- a/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/injection/CoreModuleImplTest.kt
+++ b/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/injection/CoreModuleImplTest.kt
@@ -1,6 +1,7 @@
package io.embrace.android.embracesdk.internal.injection
import androidx.test.ext.junit.runners.AndroidJUnit4
+import io.embrace.android.embracesdk.fakes.injection.FakeInitModule
import io.embrace.android.embracesdk.internal.capture.metadata.AppEnvironment
import org.junit.Assert.assertEquals
import org.junit.Assert.assertNotNull
@@ -12,10 +13,12 @@ import org.robolectric.RuntimeEnvironment
@RunWith(AndroidJUnit4::class)
internal class CoreModuleImplTest {
+ private val initModule = FakeInitModule()
+
@Test
fun testApplicationObject() {
val ctx = RuntimeEnvironment.getApplication().applicationContext
- val module = CoreModuleImpl(ctx)
+ val module = CoreModuleImpl(ctx, initModule)
assertSame(ctx, module.context)
assertSame(ctx, module.application)
assertNotNull(module.serviceRegistry)
@@ -26,7 +29,7 @@ internal class CoreModuleImplTest {
val application = RuntimeEnvironment.getApplication()
val isDebug = AppEnvironment(application.applicationInfo).isDebug
val ctx = application.applicationContext
- val module = CoreModuleImpl(ctx)
+ val module = CoreModuleImpl(ctx, initModule)
assertSame(application, module.application)
assertEquals(isDebug, module.isDebug)
}
diff --git a/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/injection/DataSourceModuleImplTest.kt b/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/injection/DataSourceModuleImplTest.kt
index 93e168ba0e..0684ff6269 100644
--- a/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/injection/DataSourceModuleImplTest.kt
+++ b/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/injection/DataSourceModuleImplTest.kt
@@ -1,6 +1,5 @@
package io.embrace.android.embracesdk.internal.injection
-import io.embrace.android.embracesdk.fakes.FakeConfigService
import io.embrace.android.embracesdk.fakes.injection.FakeInitModule
import io.embrace.android.embracesdk.fakes.injection.FakeWorkerThreadModule
import io.embrace.android.embracesdk.internal.worker.Worker
@@ -15,7 +14,6 @@ internal class DataSourceModuleImplTest {
val fakeInitModule = FakeInitModule()
val module = DataSourceModuleImpl(
fakeInitModule,
- FakeConfigService(),
FakeWorkerThreadModule(
fakeInitModule = fakeInitModule,
testWorkerName = Worker.Background.NonIoRegWorker
diff --git a/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/injection/DeliveryModuleImplTest.kt b/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/injection/DeliveryModuleImplTest.kt
index a759cf9f58..2f69cb6e37 100644
--- a/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/injection/DeliveryModuleImplTest.kt
+++ b/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/injection/DeliveryModuleImplTest.kt
@@ -8,6 +8,7 @@ import io.embrace.android.embracesdk.fakes.FakeDeliveryService
import io.embrace.android.embracesdk.fakes.FakeOpenTelemetryModule
import io.embrace.android.embracesdk.fakes.FakeRequestExecutionService
import io.embrace.android.embracesdk.fakes.behavior.FakeAutoDataCaptureBehavior
+import io.embrace.android.embracesdk.fakes.injection.FakeAndroidServicesModule
import io.embrace.android.embracesdk.fakes.injection.FakeEssentialServiceModule
import io.embrace.android.embracesdk.fakes.injection.FakeInitModule
import io.embrace.android.embracesdk.fakes.injection.FakeStorageModule
@@ -29,17 +30,19 @@ class DeliveryModuleImplTest {
@Before
fun setUp() {
configService = FakeConfigService()
+ val initModule = FakeInitModule()
module = DeliveryModuleImpl(
FakeConfigModule(configService),
- FakeInitModule(),
+ initModule,
FakeOpenTelemetryModule(),
FakeWorkerThreadModule(),
- CoreModuleImpl(ApplicationProvider.getApplicationContext()),
+ CoreModuleImpl(ApplicationProvider.getApplicationContext(), initModule),
FakeStorageModule(),
FakeEssentialServiceModule(),
+ FakeAndroidServicesModule(),
::FakeRequestExecutionService,
- { null },
- { null },
+ null,
+ null,
::FakeDeliveryService
)
}
diff --git a/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/injection/PayloadSourceModuleImplTest.kt b/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/injection/PayloadSourceModuleImplTest.kt
index 8db3dabbff..d1fe753eda 100644
--- a/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/injection/PayloadSourceModuleImplTest.kt
+++ b/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/injection/PayloadSourceModuleImplTest.kt
@@ -29,7 +29,7 @@ internal class PayloadSourceModuleImplTest {
val initModule = FakeInitModule()
val module = PayloadSourceModuleImpl(
initModule,
- CoreModuleImpl(RuntimeEnvironment.getApplication()),
+ CoreModuleImpl(RuntimeEnvironment.getApplication(), initModule),
FakeWorkerThreadModule(),
FakeSystemServiceModule(),
FakeAndroidServicesModule(),
@@ -52,7 +52,7 @@ internal class PayloadSourceModuleImplTest {
val initModule = FakeInitModule()
val module = PayloadSourceModuleImpl(
initModule,
- CoreModuleImpl(RuntimeEnvironment.getApplication()),
+ CoreModuleImpl(RuntimeEnvironment.getApplication(), initModule),
FakeWorkerThreadModule(),
FakeSystemServiceModule(),
FakeAndroidServicesModule(),
diff --git a/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/injection/SystemServiceModuleImplTest.kt b/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/injection/SystemServiceModuleImplTest.kt
index 8d6920e2a9..61f797ebdc 100644
--- a/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/injection/SystemServiceModuleImplTest.kt
+++ b/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/injection/SystemServiceModuleImplTest.kt
@@ -3,6 +3,7 @@ package io.embrace.android.embracesdk.internal.injection
import android.os.Build
import androidx.test.ext.junit.runners.AndroidJUnit4
import io.embrace.android.embracesdk.fakes.FakeVersionChecker
+import io.embrace.android.embracesdk.fakes.injection.FakeInitModule
import org.junit.Assert.assertNotNull
import org.junit.Assert.assertNull
import org.junit.Before
@@ -15,17 +16,18 @@ import org.robolectric.annotation.Config
internal class SystemServiceModuleImplTest {
private lateinit var coreModule: CoreModule
+ private val initModule = FakeInitModule()
@Before
fun setUp() {
- coreModule = createCoreModule(RuntimeEnvironment.getApplication())
+ coreModule = createCoreModule(RuntimeEnvironment.getApplication(), initModule)
}
@Config(sdk = [Build.VERSION_CODES.O])
@Test
fun testVersionChecksNew() {
val new = SystemServiceModuleImpl(
- createCoreModule(RuntimeEnvironment.getApplication()),
+ createCoreModule(RuntimeEnvironment.getApplication(), initModule),
FakeVersionChecker(true)
)
assertNotNull(new.storageManager)
diff --git a/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/logs/EmbraceLogServiceTest.kt b/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/logs/EmbraceLogServiceTest.kt
index 234283f906..280867355a 100644
--- a/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/logs/EmbraceLogServiceTest.kt
+++ b/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/logs/EmbraceLogServiceTest.kt
@@ -7,6 +7,8 @@ import io.embrace.android.embracesdk.fakes.FakeConfigService
import io.embrace.android.embracesdk.fakes.FakeLogWriter
import io.embrace.android.embracesdk.fakes.FakeSessionPropertiesService
import io.embrace.android.embracesdk.fakes.behavior.FakeLogMessageBehavior
+import io.embrace.android.embracesdk.fakes.config.FakeInstrumentedConfig
+import io.embrace.android.embracesdk.fakes.config.FakeRedactionConfig
import io.embrace.android.embracesdk.fakes.createSessionBehavior
import io.embrace.android.embracesdk.internal.arch.schema.EmbType
import io.embrace.android.embracesdk.internal.config.behavior.REDACTED_LABEL
@@ -37,7 +39,9 @@ internal class EmbraceLogServiceTest {
@Before
fun setUp() {
fakeConfigService = FakeConfigService(
- sensitiveKeysBehavior = SensitiveKeysBehaviorImpl(listOf("password"))
+ sensitiveKeysBehavior = SensitiveKeysBehaviorImpl(
+ FakeInstrumentedConfig(redaction = FakeRedactionConfig(sensitiveKeys = listOf("password"))),
+ )
)
fakeSessionPropertiesService = FakeSessionPropertiesService()
fakeLogWriter = FakeLogWriter()
@@ -105,14 +109,12 @@ internal class EmbraceLogServiceTest {
// given a config that gates info and warning logs
fakeConfigService = FakeConfigService(
sessionBehavior = createSessionBehavior(
- remoteCfg = {
- RemoteConfig(
- sessionConfig = SessionRemoteConfig(
- isEnabled = true,
- sessionComponents = emptySet() // empty set will gate everything
- )
+ remoteCfg = RemoteConfig(
+ sessionConfig = SessionRemoteConfig(
+ isEnabled = true,
+ sessionComponents = emptySet() // empty set will gate everything
)
- }
+ )
)
)
logService = createEmbraceLogService()
diff --git a/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/network/logging/EmbraceNetworkCaptureServiceTest.kt b/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/network/logging/EmbraceNetworkCaptureServiceTest.kt
index 27e25c0fa4..b304c6162f 100644
--- a/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/network/logging/EmbraceNetworkCaptureServiceTest.kt
+++ b/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/network/logging/EmbraceNetworkCaptureServiceTest.kt
@@ -4,7 +4,9 @@ import io.embrace.android.embracesdk.fakes.FakeConfigService
import io.embrace.android.embracesdk.fakes.FakeNetworkCaptureDataSource
import io.embrace.android.embracesdk.fakes.FakePreferenceService
import io.embrace.android.embracesdk.fakes.FakeSessionIdTracker
+import io.embrace.android.embracesdk.fakes.config.FakeInstrumentedConfig
import io.embrace.android.embracesdk.fakes.createNetworkBehavior
+import io.embrace.android.embracesdk.internal.comms.api.EmbraceApiUrlBuilder
import io.embrace.android.embracesdk.internal.config.remote.NetworkCaptureRuleRemoteConfig
import io.embrace.android.embracesdk.internal.config.remote.RemoteConfig
import io.embrace.android.embracesdk.internal.logging.EmbLoggerImpl
@@ -35,7 +37,7 @@ internal class EmbraceNetworkCaptureServiceTest {
fun setUp() {
cfg = RemoteConfig()
configService = FakeConfigService(
- networkBehavior = createNetworkBehavior(remoteCfg = { cfg })
+ networkBehavior = createNetworkBehavior(remoteCfg = cfg)
)
preferenceService = FakePreferenceService()
networkCaptureDataSource = FakeNetworkCaptureDataSource()
@@ -65,10 +67,9 @@ internal class EmbraceNetworkCaptureServiceTest {
@Test
fun `test capture rule doesn't capture Embrace endpoints`() {
- configService.appId = "o0o0o"
- val rule = getDefaultRule(urlRegex = "https://a-o0o0o.data.emb-api.com")
+ val rule = getDefaultRule(urlRegex = "https://a-abcde.data.emb-api.com/v2")
cfg = RemoteConfig(networkCaptureRules = setOf(rule))
- val result = getService().getNetworkCaptureRules("https://a-o0o0o.data.emb-api.com", "GET")
+ val result = getService().getNetworkCaptureRules("https://a-abcde.data.emb-api.com/v2/spans", "GET")
assertEquals(0, result.size)
}
@@ -190,14 +191,24 @@ internal class EmbraceNetworkCaptureServiceTest {
assertEquals(2, networkCaptureDataSource.loggedCalls.size)
}
- private fun getService() = EmbraceNetworkCaptureService(
- sessionIdTracker,
- preferenceService,
- { networkCaptureDataSource },
- configService,
- EmbraceSerializer(),
- EmbLoggerImpl()
- )
+ private fun getService(): EmbraceNetworkCaptureService {
+ configService = FakeConfigService(
+ networkBehavior = createNetworkBehavior(remoteCfg = cfg)
+ )
+ return EmbraceNetworkCaptureService(
+ sessionIdTracker,
+ preferenceService,
+ { networkCaptureDataSource },
+ configService,
+ EmbraceApiUrlBuilder(
+ "deviceId",
+ "1.0.0",
+ FakeInstrumentedConfig()
+ ),
+ EmbraceSerializer(),
+ EmbLoggerImpl()
+ )
+ }
private fun getDefaultRule(
id: String = "123",
diff --git a/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/prefs/EmbracePreferencesServiceTest.kt b/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/prefs/EmbracePreferencesServiceTest.kt
index 20529e7d6f..0bdef72e48 100644
--- a/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/prefs/EmbracePreferencesServiceTest.kt
+++ b/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/prefs/EmbracePreferencesServiceTest.kt
@@ -9,7 +9,6 @@ import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import io.embrace.android.embracesdk.fakes.FakeClock
import io.embrace.android.embracesdk.fakes.FakeSharedPreferences
-import io.embrace.android.embracesdk.fakes.fakeBackgroundWorker
import io.embrace.android.embracesdk.internal.serialization.EmbraceSerializer
import org.junit.Assert.assertEquals
import org.junit.Assert.assertFalse
@@ -27,7 +26,6 @@ internal class EmbracePreferencesServiceTest {
private lateinit var service: EmbracePreferencesService
private lateinit var fakeClock: FakeClock
- private val executorService = fakeBackgroundWorker()
private val context = ApplicationProvider.getApplicationContext()
@Before
@@ -35,8 +33,7 @@ internal class EmbracePreferencesServiceTest {
prefs = PreferenceManager.getDefaultSharedPreferences(context)
fakeClock = FakeClock()
service = EmbracePreferencesService(
- executorService,
- lazy { prefs },
+ prefs,
fakeClock,
EmbraceSerializer()
)
@@ -84,13 +81,6 @@ internal class EmbracePreferencesServiceTest {
assertNotNull(service.deviceIdentifier)
}
- @Test
- fun `test sdk disabled is saved`() {
- assertFalse(service.sdkDisabled)
- service.sdkDisabled = true
- assertTrue(service.sdkDisabled)
- }
-
@Test
fun `test user payer is saved`() {
assertFalse(service.userPayer)
@@ -156,13 +146,6 @@ internal class EmbracePreferencesServiceTest {
assertEquals(1234L, service.lastConfigFetchDate)
}
- @Test
- fun `test user message needs retry is saved`() {
- assertFalse(service.userMessageNeedsRetry)
- service.userMessageNeedsRetry = true
- assertTrue(service.userMessageNeedsRetry)
- }
-
@Test
fun `test session number is saved`() {
assertEquals(1, service.incrementAndGetSessionNumber())
@@ -204,8 +187,7 @@ internal class EmbracePreferencesServiceTest {
@Test
fun `test incrementAndGet returns -1 on an exception`() {
service = EmbracePreferencesService(
- executorService,
- lazy { FakeSharedPreferences(throwExceptionOnGet = true) },
+ FakeSharedPreferences(throwExceptionOnGet = true),
fakeClock,
EmbraceSerializer()
)
@@ -317,15 +299,6 @@ internal class EmbracePreferencesServiceTest {
assertEquals(version, service.embraceFlutterSdkVersion)
}
- @Test
- fun `test background activity enabled is saved`() {
- assertFalse(service.backgroundActivityEnabled)
-
- val expected = true
- service.backgroundActivityEnabled = true
- assertEquals(expected, service.backgroundActivityEnabled)
- }
-
@Test
fun `test is users first day`() {
assertFalse(service.isUsersFirstDay())
diff --git a/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/session/PayloadFactoryBaTest.kt b/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/session/PayloadFactoryBaTest.kt
index ec6771cae4..504d405629 100644
--- a/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/session/PayloadFactoryBaTest.kt
+++ b/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/session/PayloadFactoryBaTest.kt
@@ -14,10 +14,13 @@ import io.embrace.android.embracesdk.fakes.FakePreferenceService
import io.embrace.android.embracesdk.fakes.FakeProcessStateService
import io.embrace.android.embracesdk.fakes.FakeSessionIdTracker
import io.embrace.android.embracesdk.fakes.FakeUserService
+import io.embrace.android.embracesdk.fakes.createBackgroundActivityBehavior
import io.embrace.android.embracesdk.fakes.fakeSessionZygote
import io.embrace.android.embracesdk.fakes.injection.FakeInitModule
import io.embrace.android.embracesdk.internal.capture.metadata.MetadataService
import io.embrace.android.embracesdk.internal.capture.user.UserService
+import io.embrace.android.embracesdk.internal.config.remote.BackgroundActivityRemoteConfig
+import io.embrace.android.embracesdk.internal.config.remote.RemoteConfig
import io.embrace.android.embracesdk.internal.envelope.session.SessionEnvelopeSourceImpl
import io.embrace.android.embracesdk.internal.envelope.session.SessionPayloadSourceImpl
import io.embrace.android.embracesdk.internal.logging.EmbLoggerImpl
@@ -60,7 +63,7 @@ internal class PayloadFactoryBaTest {
activityService = FakeProcessStateService(isInBackground = true)
deliveryService = FakeDeliveryService()
ndkService = FakeNdkService()
- preferencesService = FakePreferenceService(backgroundActivityEnabled = true)
+ preferencesService = FakePreferenceService()
userService = FakeUserService()
val initModule = FakeInitModule(clock = clock)
spanRepository = initModule.openTelemetryModule.spanRepository
@@ -68,9 +71,10 @@ internal class PayloadFactoryBaTest {
currentSessionSpan = initModule.openTelemetryModule.currentSessionSpan
spanService = initModule.openTelemetryModule.spanService
configService = FakeConfigService(
- backgroundActivityCaptureEnabled = true
+ backgroundActivityBehavior = createBackgroundActivityBehavior(
+ remoteCfg = RemoteConfig(backgroundActivityConfig = BackgroundActivityRemoteConfig(threshold = 100f))
+ )
)
- configService.updateListeners()
blockingExecutorService = BlockingScheduledExecutorService(blockingMode = false)
}
diff --git a/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/session/PayloadFactorySessionTest.kt b/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/session/PayloadFactorySessionTest.kt
index 004c0d5ee1..a319b0dd5c 100644
--- a/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/session/PayloadFactorySessionTest.kt
+++ b/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/session/PayloadFactorySessionTest.kt
@@ -60,7 +60,6 @@ internal class PayloadFactorySessionTest {
companion object {
private val processStateService = FakeProcessStateService()
- private val clock = FakeClock()
@BeforeClass
@JvmStatic
@@ -86,13 +85,12 @@ internal class PayloadFactorySessionTest {
sessionIdTracker = FakeSessionIdTracker()
activityService = FakeProcessStateService(isInBackground = true)
ndkService = FakeNdkService()
- preferencesService = FakePreferenceService(backgroundActivityEnabled = true)
+ preferencesService = FakePreferenceService()
userService = FakeUserService()
val initModule = FakeInitModule(clock = clock)
spanRepository = initModule.openTelemetryModule.spanRepository
currentSessionSpan = initModule.openTelemetryModule.currentSessionSpan
spanService = initModule.openTelemetryModule.spanService
- configService.updateListeners()
blockingExecutorService = BlockingScheduledExecutorService(blockingMode = false)
}
diff --git a/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/session/SessionOrchestrationModuleImplTest.kt b/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/session/SessionOrchestrationModuleImplTest.kt
index 67b66e3ea5..8e838904be 100644
--- a/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/session/SessionOrchestrationModuleImplTest.kt
+++ b/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/session/SessionOrchestrationModuleImplTest.kt
@@ -3,6 +3,7 @@ package io.embrace.android.embracesdk.internal.session
import io.embrace.android.embracesdk.fakes.FakeConfigModule
import io.embrace.android.embracesdk.fakes.FakeConfigService
import io.embrace.android.embracesdk.fakes.FakeStartupService
+import io.embrace.android.embracesdk.fakes.createBackgroundActivityBehavior
import io.embrace.android.embracesdk.fakes.injection.FakeAndroidServicesModule
import io.embrace.android.embracesdk.fakes.injection.FakeDeliveryModule
import io.embrace.android.embracesdk.fakes.injection.FakeEssentialServiceModule
@@ -10,11 +11,12 @@ import io.embrace.android.embracesdk.fakes.injection.FakeInitModule
import io.embrace.android.embracesdk.fakes.injection.FakeLogModule
import io.embrace.android.embracesdk.fakes.injection.FakePayloadSourceModule
import io.embrace.android.embracesdk.fakes.injection.FakeWorkerThreadModule
+import io.embrace.android.embracesdk.internal.config.remote.BackgroundActivityRemoteConfig
+import io.embrace.android.embracesdk.internal.config.remote.RemoteConfig
import io.embrace.android.embracesdk.internal.injection.SessionOrchestrationModuleImpl
import io.embrace.android.embracesdk.internal.injection.createDataSourceModule
import io.embrace.android.embracesdk.internal.worker.Worker
import org.junit.Assert.assertNotNull
-import org.junit.Assert.assertTrue
import org.junit.Test
internal class SessionOrchestrationModuleImplTest {
@@ -30,7 +32,6 @@ internal class SessionOrchestrationModuleImplTest {
fun testDefaultImplementations() {
val dataSourceModule = createDataSourceModule(
initModule,
- configService,
workerThreadModule
)
val module = SessionOrchestrationModuleImpl(
@@ -48,10 +49,6 @@ internal class SessionOrchestrationModuleImplTest {
assertNotNull(module.payloadMessageCollator)
assertNotNull(module.payloadFactory)
assertNotNull(module.sessionOrchestrator)
- assertTrue(
- configService.listeners.single().javaClass.toString()
- .contains("DataCaptureOrchestrator")
- )
}
@Test
@@ -59,7 +56,6 @@ internal class SessionOrchestrationModuleImplTest {
val configModule = createEnabledBehavior()
val dataSourceModule = createDataSourceModule(
initModule,
- configService,
workerThreadModule
)
@@ -83,7 +79,9 @@ internal class SessionOrchestrationModuleImplTest {
private fun createEnabledBehavior(): FakeConfigModule {
return FakeConfigModule(
configService = FakeConfigService(
- backgroundActivityCaptureEnabled = true
+ backgroundActivityBehavior = createBackgroundActivityBehavior(
+ remoteCfg = RemoteConfig(backgroundActivityConfig = BackgroundActivityRemoteConfig(threshold = 100f))
+ ),
)
)
}
diff --git a/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/session/message/PayloadFactoryImplTest.kt b/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/session/message/PayloadFactoryImplTest.kt
index df0566353a..60569154e4 100644
--- a/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/session/message/PayloadFactoryImplTest.kt
+++ b/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/session/message/PayloadFactoryImplTest.kt
@@ -6,7 +6,10 @@ import io.embrace.android.embracesdk.fakes.FakeEnvelopeResourceSource
import io.embrace.android.embracesdk.fakes.FakeGatingService
import io.embrace.android.embracesdk.fakes.FakePreferenceService
import io.embrace.android.embracesdk.fakes.FakeSessionPayloadSource
+import io.embrace.android.embracesdk.fakes.createBackgroundActivityBehavior
import io.embrace.android.embracesdk.fakes.injection.FakeInitModule
+import io.embrace.android.embracesdk.internal.config.remote.BackgroundActivityRemoteConfig
+import io.embrace.android.embracesdk.internal.config.remote.RemoteConfig
import io.embrace.android.embracesdk.internal.envelope.session.SessionEnvelopeSourceImpl
import io.embrace.android.embracesdk.internal.session.lifecycle.ProcessState
import io.embrace.android.embracesdk.internal.session.lifecycle.ProcessState.BACKGROUND
@@ -54,7 +57,9 @@ internal class PayloadFactoryImplTest {
@Test
fun `verify expected payloads with ba enabled`() {
- configService.backgroundActivityCaptureEnabled = true
+ configService.backgroundActivityBehavior = createBackgroundActivityBehavior(
+ remoteCfg = RemoteConfig(backgroundActivityConfig = BackgroundActivityRemoteConfig(threshold = 100f))
+ )
verifyPayloadWithState(state = FOREGROUND, zygoteCreated = true, startNewSession = true)
verifyPayloadWithState(state = BACKGROUND, zygoteCreated = true, startNewSession = true)
verifyPayloadWithManual()
@@ -62,7 +67,9 @@ internal class PayloadFactoryImplTest {
@Test
fun `verify expected payloads with ba disabled`() {
- configService.backgroundActivityCaptureEnabled = false
+ configService.backgroundActivityBehavior = createBackgroundActivityBehavior(
+ remoteCfg = RemoteConfig(backgroundActivityConfig = BackgroundActivityRemoteConfig(threshold = 0f))
+ )
verifyPayloadWithState(state = FOREGROUND, zygoteCreated = true, startNewSession = false)
verifyPayloadWithState(state = BACKGROUND, zygoteCreated = false, startNewSession = false)
verifyPayloadWithManual()
diff --git a/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/session/message/PayloadMessageCollatorImplTest.kt b/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/session/message/PayloadMessageCollatorImplTest.kt
index 62b2898fe7..be09ba24da 100644
--- a/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/session/message/PayloadMessageCollatorImplTest.kt
+++ b/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/session/message/PayloadMessageCollatorImplTest.kt
@@ -37,7 +37,7 @@ internal class PayloadMessageCollatorImplTest {
@Before
fun setUp() {
initModule = FakeInitModule()
- coreModule = CoreModuleImpl(RuntimeEnvironment.getApplication())
+ coreModule = CoreModuleImpl(RuntimeEnvironment.getApplication(), initModule)
gatingService = FakeGatingService()
val sessionEnvelopeSource = SessionEnvelopeSourceImpl(
metadataSource = FakeEnvelopeMetadataSource(),
diff --git a/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/session/orchestrator/SessionOrchestratorTest.kt b/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/session/orchestrator/SessionOrchestratorTest.kt
index 72c2f3c421..34c06072e7 100644
--- a/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/session/orchestrator/SessionOrchestratorTest.kt
+++ b/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/session/orchestrator/SessionOrchestratorTest.kt
@@ -17,11 +17,14 @@ import io.embrace.android.embracesdk.fakes.FakeStartupService
import io.embrace.android.embracesdk.fakes.FakeUserService
import io.embrace.android.embracesdk.fakes.FakeV2PayloadCollator
import io.embrace.android.embracesdk.fakes.behavior.FakeSessionBehavior
+import io.embrace.android.embracesdk.fakes.createBackgroundActivityBehavior
import io.embrace.android.embracesdk.fakes.fakeBackgroundWorker
import io.embrace.android.embracesdk.internal.arch.DataCaptureOrchestrator
import io.embrace.android.embracesdk.internal.arch.datasource.DataSourceState
import io.embrace.android.embracesdk.internal.capture.session.SessionPropertiesService
import io.embrace.android.embracesdk.internal.clock.nanosToMillis
+import io.embrace.android.embracesdk.internal.config.remote.BackgroundActivityRemoteConfig
+import io.embrace.android.embracesdk.internal.config.remote.RemoteConfig
import io.embrace.android.embracesdk.internal.delivery.caching.PayloadCachingService
import io.embrace.android.embracesdk.internal.delivery.caching.PayloadCachingServiceImpl
import io.embrace.android.embracesdk.internal.logging.EmbLogger
@@ -65,7 +68,11 @@ internal class SessionOrchestratorTest {
fun setUp() {
clock = FakeClock()
logger = EmbLoggerImpl()
- configService = FakeConfigService(backgroundActivityCaptureEnabled = true)
+ configService = FakeConfigService(
+ backgroundActivityBehavior = createBackgroundActivityBehavior(
+ remoteCfg = RemoteConfig(backgroundActivityConfig = BackgroundActivityRemoteConfig(threshold = 100f))
+ )
+ )
}
@Test
@@ -254,7 +261,9 @@ internal class SessionOrchestratorTest {
@Test
fun `end with crash in background`() {
configService = FakeConfigService(
- backgroundActivityCaptureEnabled = true,
+ backgroundActivityBehavior = createBackgroundActivityBehavior(
+ remoteCfg = RemoteConfig(backgroundActivityConfig = BackgroundActivityRemoteConfig(threshold = 100f))
+ )
)
createOrchestrator(true)
orchestrator.handleCrash("crashId")
@@ -264,7 +273,9 @@ internal class SessionOrchestratorTest {
@Test
fun `end with crash in foreground`() {
configService = FakeConfigService(
- backgroundActivityCaptureEnabled = true,
+ backgroundActivityBehavior = createBackgroundActivityBehavior(
+ remoteCfg = RemoteConfig(backgroundActivityConfig = BackgroundActivityRemoteConfig(threshold = 100f))
+ )
)
createOrchestrator(false)
orchestrator.handleCrash("crashId")
@@ -369,7 +380,6 @@ internal class SessionOrchestratorTest {
)
fakeDataSource = FakeDataSource(RuntimeEnvironment.getApplication())
dataCaptureOrchestrator = DataCaptureOrchestrator(
- configService,
fakeBackgroundWorker(),
logger
).apply {
diff --git a/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/spans/EmbraceSpanFactoryImplTest.kt b/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/spans/EmbraceSpanFactoryImplTest.kt
index 60a2f0f670..fab712cbb0 100644
--- a/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/spans/EmbraceSpanFactoryImplTest.kt
+++ b/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/spans/EmbraceSpanFactoryImplTest.kt
@@ -4,6 +4,8 @@ import io.embrace.android.embracesdk.fakes.FakeClock
import io.embrace.android.embracesdk.fakes.FakePayloadCachingService
import io.embrace.android.embracesdk.fakes.FakePersistableEmbraceSpan
import io.embrace.android.embracesdk.fakes.FakeTracer
+import io.embrace.android.embracesdk.fakes.config.FakeInstrumentedConfig
+import io.embrace.android.embracesdk.fakes.config.FakeRedactionConfig
import io.embrace.android.embracesdk.fakes.injection.FakeInitModule
import io.embrace.android.embracesdk.internal.arch.schema.EmbType
import io.embrace.android.embracesdk.internal.arch.schema.PrivateSpan
@@ -39,7 +41,9 @@ internal class EmbraceSpanFactoryImplTest {
tracer = tracer,
openTelemetryClock = initModule.openTelemetryModule.openTelemetryClock,
spanRepository = spanRepository,
- sensitiveKeysBehavior = SensitiveKeysBehaviorImpl(listOf("password")),
+ sensitiveKeysBehavior = SensitiveKeysBehaviorImpl(
+ FakeInstrumentedConfig(redaction = FakeRedactionConfig(sensitiveKeys = listOf("password"))),
+ ),
)
}
diff --git a/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/spans/EmbraceSpanImplTest.kt b/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/spans/EmbraceSpanImplTest.kt
index b61335b2dc..8eecb7c963 100644
--- a/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/spans/EmbraceSpanImplTest.kt
+++ b/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/spans/EmbraceSpanImplTest.kt
@@ -2,6 +2,8 @@ package io.embrace.android.embracesdk.internal.spans
import io.embrace.android.embracesdk.fakes.FakeClock
import io.embrace.android.embracesdk.fakes.FakeOpenTelemetryClock
+import io.embrace.android.embracesdk.fakes.config.FakeInstrumentedConfig
+import io.embrace.android.embracesdk.fakes.config.FakeRedactionConfig
import io.embrace.android.embracesdk.fakes.injection.FakeInitModule
import io.embrace.android.embracesdk.fixtures.MAX_LENGTH_ATTRIBUTE_KEY
import io.embrace.android.embracesdk.fixtures.MAX_LENGTH_ATTRIBUTE_KEY_FOR_INTERNAL_SPAN
@@ -53,7 +55,9 @@ internal class EmbraceSpanImplTest {
.setTracerProvider(SdkTracerProvider.builder().build()).build()
.getTracer(EmbraceSpanImplTest::class.java.name)
- private val sensitiveKeysBehavior = SensitiveKeysBehaviorImpl(listOf("password"))
+ private val sensitiveKeysBehavior = SensitiveKeysBehaviorImpl(
+ FakeInstrumentedConfig(redaction = FakeRedactionConfig(sensitiveKeys = listOf("password"))),
+ )
@Before
fun setup() {
diff --git a/embrace-android-core/src/test/resources/remote_config_response.json b/embrace-android-core/src/test/resources/remote_config_response.json
deleted file mode 100644
index 38f601e5d4..0000000000
--- a/embrace-android-core/src/test/resources/remote_config_response.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "ls": 100,
- "event_limits": {},
- "offset": 0,
- "personas": [],
- "session_control": {
- "enable": true,
- "async_end": false
- },
- "threshold": 100,
- "ui": {
- "views": 100
- },
- "urlconnection_request_enabled": true
-}
\ No newline at end of file
diff --git a/embrace-android-delivery/src/main/kotlin/io/embrace/android/embracesdk/internal/delivery/execution/OkHttpRequestExecutionService.kt b/embrace-android-delivery/src/main/kotlin/io/embrace/android/embracesdk/internal/delivery/execution/OkHttpRequestExecutionService.kt
index 7372fb568f..019a7bc68b 100644
--- a/embrace-android-delivery/src/main/kotlin/io/embrace/android/embracesdk/internal/delivery/execution/OkHttpRequestExecutionService.kt
+++ b/embrace-android-delivery/src/main/kotlin/io/embrace/android/embracesdk/internal/delivery/execution/OkHttpRequestExecutionService.kt
@@ -9,7 +9,6 @@ import io.embrace.android.embracesdk.internal.logging.InternalErrorType
import okhttp3.Headers.Companion.toHeaders
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.OkHttpClient
-import okhttp3.Protocol
import okhttp3.Request
import okhttp3.RequestBody
import okio.BufferedSink
@@ -17,25 +16,16 @@ import okio.buffer
import okio.source
import java.io.IOException
import java.io.InputStream
-import java.util.concurrent.TimeUnit
class OkHttpRequestExecutionService(
+ private val okHttpClient: OkHttpClient,
private val coreBaseUrl: String,
private val lazyDeviceId: Lazy,
private val appId: String,
private val embraceVersionName: String,
private val logger: EmbLogger,
- connectionTimeoutSeconds: Long = DEFAULT_CONNECTION_TIMEOUT_SECONDS,
- readTimeoutSeconds: Long = DEFAULT_READ_TIMEOUT_SECONDS,
) : RequestExecutionService {
- private val okHttpClient = OkHttpClient()
- .newBuilder()
- .protocols(listOf(Protocol.HTTP_2, Protocol.HTTP_1_1))
- .connectTimeout(connectionTimeoutSeconds, TimeUnit.SECONDS)
- .readTimeout(readTimeoutSeconds, TimeUnit.SECONDS)
- .build()
-
override fun attemptHttpRequest(
payloadStream: () -> InputStream,
envelopeType: SupportedEnvelopeType,
@@ -79,7 +69,7 @@ class OkHttpRequestExecutionService(
}
private fun Endpoint.getApiRequestFromEndpoint(): ApiRequestV2 = ApiRequestV2(
- url = "$coreBaseUrl/v2/${this.path}",
+ url = "$coreBaseUrl${this.path}",
appId = appId,
deviceId = lazyDeviceId.value,
contentEncoding = "gzip",
@@ -87,8 +77,6 @@ class OkHttpRequestExecutionService(
)
private companion object {
- const val DEFAULT_CONNECTION_TIMEOUT_SECONDS = 10L
- const val DEFAULT_READ_TIMEOUT_SECONDS = 60L
private val mediaType = "application/json".toMediaType()
class ApiRequestBody(
diff --git a/embrace-android-delivery/src/test/kotlin/io/embrace/android/embracesdk/internal/delivery/execution/OkHttpRequestExecutionServiceTest.kt b/embrace-android-delivery/src/test/kotlin/io/embrace/android/embracesdk/internal/delivery/execution/OkHttpRequestExecutionServiceTest.kt
index d5eafd4109..afda048a10 100644
--- a/embrace-android-delivery/src/test/kotlin/io/embrace/android/embracesdk/internal/delivery/execution/OkHttpRequestExecutionServiceTest.kt
+++ b/embrace-android-delivery/src/test/kotlin/io/embrace/android/embracesdk/internal/delivery/execution/OkHttpRequestExecutionServiceTest.kt
@@ -4,6 +4,7 @@ import io.embrace.android.embracesdk.fakes.FakeEmbLogger
import io.embrace.android.embracesdk.internal.delivery.PayloadType
import io.embrace.android.embracesdk.internal.delivery.SupportedEnvelopeType
import okhttp3.Headers.Companion.toHeaders
+import okhttp3.OkHttpClient
import okhttp3.Protocol
import okhttp3.mockwebserver.MockResponse
import okhttp3.mockwebserver.MockWebServer
@@ -15,12 +16,14 @@ import org.junit.Before
import org.junit.Test
import java.net.SocketTimeoutException
import java.net.UnknownHostException
+import java.util.concurrent.TimeUnit
class OkHttpRequestExecutionServiceTest {
private lateinit var requestExecutionService: OkHttpRequestExecutionService
private lateinit var server: MockWebServer
private lateinit var testServerUrl: String
private lateinit var logger: FakeEmbLogger
+ private lateinit var client: OkHttpClient
private val testAppId = "test_app_id"
private val testDeviceId = "test_device_id"
@@ -48,15 +51,20 @@ class OkHttpRequestExecutionServiceTest {
protocols = listOf(Protocol.HTTP_2, Protocol.HTTP_1_1)
start()
}
- testServerUrl = server.url("").toString().removeSuffix("/")
+ testServerUrl = server.url("").toString()
+ client = OkHttpClient()
+ .newBuilder()
+ .protocols(listOf(Protocol.HTTP_2, Protocol.HTTP_1_1))
+ .connectTimeout(1, TimeUnit.SECONDS)
+ .readTimeout(1, TimeUnit.SECONDS)
+ .build()
requestExecutionService = OkHttpRequestExecutionService(
+ okHttpClient = client,
coreBaseUrl = testServerUrl,
lazyDeviceId = lazy { testDeviceId },
appId = testAppId,
embraceVersionName = testEmbraceVersionName,
logger = logger,
- connectionTimeoutSeconds = 1L,
- readTimeoutSeconds = 1L,
)
}
@@ -69,7 +77,8 @@ class OkHttpRequestExecutionServiceTest {
fun `return incomplete if the server does not exist`() {
// given a request execution service with a non existent url
requestExecutionService = OkHttpRequestExecutionService(
- coreBaseUrl = "https://nonexistenturl:1565",
+ okHttpClient = client,
+ coreBaseUrl = "https://nonexistenturl:1565/",
lazyDeviceId = lazy { testDeviceId },
appId = testAppId,
embraceVersionName = testEmbraceVersionName,
diff --git a/embrace-android-features/src/main/kotlin/io/embrace/android/embracesdk/internal/anr/ndk/NativeThreadSamplerInstaller.kt b/embrace-android-features/src/main/kotlin/io/embrace/android/embracesdk/internal/anr/ndk/NativeThreadSamplerInstaller.kt
index 0b5dbeb306..9b12592cb1 100644
--- a/embrace-android-features/src/main/kotlin/io/embrace/android/embracesdk/internal/anr/ndk/NativeThreadSamplerInstaller.kt
+++ b/embrace-android-features/src/main/kotlin/io/embrace/android/embracesdk/internal/anr/ndk/NativeThreadSamplerInstaller.kt
@@ -55,32 +55,12 @@ class NativeThreadSamplerInstaller(
if (configService.anrBehavior.isUnityAnrCaptureEnabled()) {
monitorCurrentThread(sampler, anrService)
}
-
- // always install the handler. if config subsequently changes we take the decision
- // to just ignore anr intervals, rather than attempting to uninstall the handler
- configService.addListener {
- onConfigChange(configService, sampler, anrService)
- }
}
private fun isMonitoringCurrentThread(): Boolean {
return isMonitoring.get() && Thread.currentThread().id == currentThread?.id
}
- private fun onConfigChange(
- configService: ConfigService,
- sampler: NativeThreadSamplerService,
- anrService: AnrService,
- ) {
- targetHandler?.post(
- Runnable {
- if (configService.anrBehavior.isUnityAnrCaptureEnabled() && !isMonitoring.get()) {
- monitorCurrentThread(sampler, anrService)
- }
- }
- )
- }
-
private fun monitorCurrentThread(sampler: NativeThreadSamplerService, anrService: AnrService) {
synchronized(this) {
if (!isMonitoring.get()) {
diff --git a/embrace-android-features/src/main/kotlin/io/embrace/android/embracesdk/internal/injection/FeatureModuleImpl.kt b/embrace-android-features/src/main/kotlin/io/embrace/android/embracesdk/internal/injection/FeatureModuleImpl.kt
index adc2bde58d..f208561ece 100644
--- a/embrace-android-features/src/main/kotlin/io/embrace/android/embracesdk/internal/injection/FeatureModuleImpl.kt
+++ b/embrace-android-features/src/main/kotlin/io/embrace/android/embracesdk/internal/injection/FeatureModuleImpl.kt
@@ -198,7 +198,7 @@ internal class FeatureModuleImpl(
override val applicationExitInfoDataSource: DataSourceState by dataSourceState {
DataSourceState(
factory = { aeiService },
- configGate = { configService.isAppExitInfoCaptureEnabled() }
+ configGate = { configService.appExitInfoBehavior.isAeiCaptureEnabled() }
)
}
diff --git a/embrace-android-features/src/test/java/io/embrace/android/embracesdk/internal/anr/detection/LivenessCheckSchedulerTest.kt b/embrace-android-features/src/test/java/io/embrace/android/embracesdk/internal/anr/detection/LivenessCheckSchedulerTest.kt
index fef31f841c..67e399d010 100644
--- a/embrace-android-features/src/test/java/io/embrace/android/embracesdk/internal/anr/detection/LivenessCheckSchedulerTest.kt
+++ b/embrace-android-features/src/test/java/io/embrace/android/embracesdk/internal/anr/detection/LivenessCheckSchedulerTest.kt
@@ -7,6 +7,7 @@ import io.embrace.android.embracesdk.fakes.FakeConfigService
import io.embrace.android.embracesdk.fakes.createAnrBehavior
import io.embrace.android.embracesdk.internal.config.ConfigService
import io.embrace.android.embracesdk.internal.config.remote.AnrRemoteConfig
+import io.embrace.android.embracesdk.internal.config.remote.RemoteConfig
import io.embrace.android.embracesdk.internal.logging.EmbLogger
import io.embrace.android.embracesdk.internal.logging.EmbLoggerImpl
import io.embrace.android.embracesdk.internal.worker.BackgroundWorker
@@ -40,7 +41,7 @@ internal class LivenessCheckSchedulerTest {
anrMonitorThread = AtomicReference(Thread.currentThread())
cfg = AnrRemoteConfig()
fakeClock = FakeClock(160982340900)
- configService = FakeConfigService(anrBehavior = createAnrBehavior { cfg })
+ configService = FakeConfigService(anrBehavior = createAnrBehavior(remoteCfg = RemoteConfig(anrConfig = cfg)))
anrExecutorService = BlockingScheduledExecutorService(fakeClock)
logger = EmbLoggerImpl()
looper = mockk {
@@ -146,21 +147,6 @@ internal class LivenessCheckSchedulerTest {
assertEquals(160982340900, state.lastMonitorThreadResponseMs)
}
- @Test
- fun testExecuteHealthCheckDifferentIntervalMs() {
- // alter the intervalMs to trigger rescheduling
- scheduler.startMonitoringThread()
- anrExecutorService.runCurrentlyBlocked()
- assertEquals(fakeClock.now(), state.lastMonitorThreadResponseMs)
- cfg = cfg.copy(sampleIntervalMs = 10)
- assertEquals(1, anrExecutorService.scheduledTasksCount())
- anrExecutorService.moveForwardAndRunBlocked(100)
- anrExecutorService.runCurrentlyBlocked()
- anrExecutorService.moveForwardAndRunBlocked(10)
- assertEquals(fakeClock.now(), state.lastMonitorThreadResponseMs)
- assertEquals(1, anrExecutorService.scheduledTasksCount())
- }
-
@Test
fun `starting monitoring thread twice does not result in multiple recurring tasks`() {
repeat(2) {
diff --git a/embrace-android-features/src/test/java/io/embrace/android/embracesdk/internal/anr/ndk/EmbraceNativeThreadSamplerServiceTest.kt b/embrace-android-features/src/test/java/io/embrace/android/embracesdk/internal/anr/ndk/EmbraceNativeThreadSamplerServiceTest.kt
index 2773fd5355..f41d45fa4c 100644
--- a/embrace-android-features/src/test/java/io/embrace/android/embracesdk/internal/anr/ndk/EmbraceNativeThreadSamplerServiceTest.kt
+++ b/embrace-android-features/src/test/java/io/embrace/android/embracesdk/internal/anr/ndk/EmbraceNativeThreadSamplerServiceTest.kt
@@ -11,6 +11,7 @@ import io.embrace.android.embracesdk.internal.config.ConfigService
import io.embrace.android.embracesdk.internal.config.behavior.AnrBehavior
import io.embrace.android.embracesdk.internal.config.remote.AllowedNdkSampleMethod
import io.embrace.android.embracesdk.internal.config.remote.AnrRemoteConfig
+import io.embrace.android.embracesdk.internal.config.remote.RemoteConfig
import io.embrace.android.embracesdk.internal.config.remote.Unwinder
import io.embrace.android.embracesdk.internal.payload.NativeThreadAnrInterval
import io.embrace.android.embracesdk.internal.payload.NativeThreadAnrSample
@@ -46,7 +47,12 @@ internal class EmbraceNativeThreadSamplerServiceTest {
@Before
fun setUp() {
cfg = AnrRemoteConfig(pctNativeThreadAnrSamplingEnabled = 100f)
- anrBehavior = createAnrBehavior { cfg }
+ setupSampler()
+ every { random.nextInt(any()) } returns 0
+ }
+
+ private fun setupSampler() {
+ anrBehavior = createAnrBehavior(remoteCfg = RemoteConfig(anrConfig = cfg))
configService = FakeConfigService(anrBehavior = anrBehavior)
sharedObjectLoader = FakeSharedObjectLoader()
delegate = mockk(relaxed = true)
@@ -62,7 +68,6 @@ internal class EmbraceNativeThreadSamplerServiceTest {
FakeDeviceArchitecture(),
sharedObjectLoader
)
- every { random.nextInt(any()) } returns 0
}
@Test
@@ -90,6 +95,7 @@ internal class EmbraceNativeThreadSamplerServiceTest {
@Test
fun testSessionEndDisabledSampling() {
cfg = cfg.copy(pctNativeThreadAnrSamplingEnabled = 0f)
+ setupSampler()
sampler.intervals = mutableListOf(obj)
simulateUnityThreadSample()
assertNull(sampler.getCapturedIntervals(false))
@@ -210,6 +216,7 @@ internal class EmbraceNativeThreadSamplerServiceTest {
),
ignoreNativeThreadAnrSamplingAllowlist = false
)
+ setupSampler()
val unityPlayer =
StackTraceElement("com.unity3d.player.UnityPlayer", "pauseUnity", null, -1)
@@ -252,6 +259,7 @@ internal class EmbraceNativeThreadSamplerServiceTest {
cfg = cfg.copy(
ignoreNativeThreadAnrSamplingAllowlist = false
)
+ setupSampler()
assertEquals(-1, sampler.count)
assertEquals(-1, sampler.factor)
assertTrue(sampler.ignored)
@@ -268,6 +276,7 @@ internal class EmbraceNativeThreadSamplerServiceTest {
cfg = cfg.copy(
pctNativeThreadAnrSamplingEnabled = 0f
)
+ setupSampler()
sampler.onThreadBlocked(Thread.currentThread(), 0)
verify(exactly = 0) { delegate.startSampling(any(), any()) }
@@ -281,6 +290,7 @@ internal class EmbraceNativeThreadSamplerServiceTest {
cfg = cfg.copy(
ignoreNativeThreadAnrSamplingAllowlist = false
)
+ setupSampler()
sampler.onThreadBlocked(Thread.currentThread(), 0)
repeat(10) {
@@ -294,6 +304,7 @@ internal class EmbraceNativeThreadSamplerServiceTest {
cfg = cfg.copy(
pctNativeThreadAnrSamplingEnabled = 0f
)
+ setupSampler()
sampler.onThreadBlocked(Thread.currentThread(), 0)
repeat(10) {
diff --git a/embrace-android-features/src/test/java/io/embrace/android/embracesdk/internal/capture/crumbs/BreadcrumbDataSourceTest.kt b/embrace-android-features/src/test/java/io/embrace/android/embracesdk/internal/capture/crumbs/BreadcrumbDataSourceTest.kt
index 39dfae0f7a..c3e15a1de1 100644
--- a/embrace-android-features/src/test/java/io/embrace/android/embracesdk/internal/capture/crumbs/BreadcrumbDataSourceTest.kt
+++ b/embrace-android-features/src/test/java/io/embrace/android/embracesdk/internal/capture/crumbs/BreadcrumbDataSourceTest.kt
@@ -1,9 +1,9 @@
package io.embrace.android.embracesdk.internal.capture.crumbs
import io.embrace.android.embracesdk.arch.assertIsType
-import io.embrace.android.embracesdk.fakes.FakeBreadcrumbBehavior
import io.embrace.android.embracesdk.fakes.FakeCurrentSessionSpan
import io.embrace.android.embracesdk.fakes.FakeEmbLogger
+import io.embrace.android.embracesdk.fakes.behavior.FakeBreadcrumbBehavior
import io.embrace.android.embracesdk.internal.arch.schema.EmbType
import org.junit.Assert.assertEquals
import org.junit.Before
diff --git a/embrace-android-features/src/test/java/io/embrace/android/embracesdk/internal/capture/crumbs/WebViewUrlDataSourceTest.kt b/embrace-android-features/src/test/java/io/embrace/android/embracesdk/internal/capture/crumbs/WebViewUrlDataSourceTest.kt
index fcd18f2343..6d7a756b03 100644
--- a/embrace-android-features/src/test/java/io/embrace/android/embracesdk/internal/capture/crumbs/WebViewUrlDataSourceTest.kt
+++ b/embrace-android-features/src/test/java/io/embrace/android/embracesdk/internal/capture/crumbs/WebViewUrlDataSourceTest.kt
@@ -1,8 +1,8 @@
package io.embrace.android.embracesdk.internal.capture.crumbs
-import io.embrace.android.embracesdk.fakes.FakeBreadcrumbBehavior
import io.embrace.android.embracesdk.fakes.FakeConfigService
import io.embrace.android.embracesdk.fakes.FakeCurrentSessionSpan
+import io.embrace.android.embracesdk.fakes.behavior.FakeBreadcrumbBehavior
import io.embrace.android.embracesdk.internal.arch.schema.EmbType
import io.embrace.android.embracesdk.internal.config.ConfigService
import io.embrace.android.embracesdk.internal.logging.EmbLoggerImpl
diff --git a/embrace-android-features/src/test/java/io/embrace/android/embracesdk/internal/injection/FeatureModuleImplTest.kt b/embrace-android-features/src/test/java/io/embrace/android/embracesdk/internal/injection/FeatureModuleImplTest.kt
index 9dd0bb706e..2ec60b7d09 100644
--- a/embrace-android-features/src/test/java/io/embrace/android/embracesdk/internal/injection/FeatureModuleImplTest.kt
+++ b/embrace-android-features/src/test/java/io/embrace/android/embracesdk/internal/injection/FeatureModuleImplTest.kt
@@ -18,10 +18,11 @@ internal class FeatureModuleImplTest {
@Test
fun testFeatureModule() {
val registry = FakeFeatureRegistry()
+ val initModule = FakeInitModule()
val module = FeatureModuleImpl(
featureRegistry = registry,
- coreModule = createCoreModule(mockk(relaxed = true)),
- initModule = FakeInitModule(),
+ coreModule = createCoreModule(mockk(relaxed = true), initModule),
+ initModule = initModule,
otelModule = FakeOpenTelemetryModule(),
workerThreadModule = FakeWorkerThreadModule(),
systemServiceModule = FakeSystemServiceModule(),
diff --git a/embrace-android-features/src/test/java/io/embrace/android/embracesdk/internal/injection/NativeFeatureModuleImplTest.kt b/embrace-android-features/src/test/java/io/embrace/android/embracesdk/internal/injection/NativeFeatureModuleImplTest.kt
index 2015cc7ac5..19dc14a2a4 100644
--- a/embrace-android-features/src/test/java/io/embrace/android/embracesdk/internal/injection/NativeFeatureModuleImplTest.kt
+++ b/embrace-android-features/src/test/java/io/embrace/android/embracesdk/internal/injection/NativeFeatureModuleImplTest.kt
@@ -20,9 +20,10 @@ internal class NativeFeatureModuleImplTest {
@Test
fun testDefaultImplementations() {
+ val initModule = FakeInitModule()
val module = NativeFeatureModuleImpl(
- FakeInitModule(),
- CoreModuleImpl(RuntimeEnvironment.getApplication()),
+ initModule,
+ CoreModuleImpl(RuntimeEnvironment.getApplication(), initModule),
FakeStorageModule(),
FakeEssentialServiceModule(),
FakeConfigModule(),
diff --git a/embrace-android-features/src/test/java/io/embrace/android/embracesdk/internal/injection/StorageModuleImplTest.kt b/embrace-android-features/src/test/java/io/embrace/android/embracesdk/internal/injection/StorageModuleImplTest.kt
index 9d35f24f6e..dbb6bcd8c9 100644
--- a/embrace-android-features/src/test/java/io/embrace/android/embracesdk/internal/injection/StorageModuleImplTest.kt
+++ b/embrace-android-features/src/test/java/io/embrace/android/embracesdk/internal/injection/StorageModuleImplTest.kt
@@ -14,7 +14,7 @@ internal class StorageModuleImplTest {
@Test
fun testDefaultImplementations() {
val initModule = FakeInitModule()
- val coreModule = CoreModuleImpl(RuntimeEnvironment.getApplication())
+ val coreModule = CoreModuleImpl(RuntimeEnvironment.getApplication(), initModule)
val module = createStorageModuleSupplier(
initModule = initModule,
coreModule = coreModule,
@@ -22,7 +22,6 @@ internal class StorageModuleImplTest {
)
assertNotNull(module.storageService)
- assertNotNull(module.cache)
assertNotNull(module.cacheService)
assertNotNull(module.deliveryCacheManager)
assertNotNull(module.storageService)
diff --git a/embrace-android-infra/src/main/kotlin/io/embrace/android/embracesdk/internal/logging/InternalErrorType.kt b/embrace-android-infra/src/main/kotlin/io/embrace/android/embracesdk/internal/logging/InternalErrorType.kt
index 6a0cc58b19..e1326504ff 100644
--- a/embrace-android-infra/src/main/kotlin/io/embrace/android/embracesdk/internal/logging/InternalErrorType.kt
+++ b/embrace-android-infra/src/main/kotlin/io/embrace/android/embracesdk/internal/logging/InternalErrorType.kt
@@ -10,13 +10,11 @@ enum class InternalErrorType {
ENABLE_DATA_CAPTURE,
NETWORK_STATUS_CAPTURE_FAIL,
SCREEN_RES_CAPTURE_FAIL,
- CONFIG_LISTENER_FAIL,
MEMORY_CLEAN_LISTENER_FAIL,
FG_SESSION_CACHE_FAIL,
ACTIVITY_LISTENER_FAIL,
PROCESS_STATE_CALLBACK_FAIL,
ANR_HEARTBEAT_CHECK_FAIL,
- CFG_CHANGE_DATA_CAPTURE_FAIL,
SESSION_CHANGE_DATA_CAPTURE_FAIL,
DATA_SOURCE_DATA_CAPTURE_FAIL,
DISK_STAT_CAPTURE_FAIL,
diff --git a/embrace-android-payload/src/main/kotlin/io/embrace/android/embracesdk/internal/comms/api/CachedConfig.kt b/embrace-android-payload/src/main/kotlin/io/embrace/android/embracesdk/internal/comms/api/CachedConfig.kt
deleted file mode 100644
index bb838e1c6f..0000000000
--- a/embrace-android-payload/src/main/kotlin/io/embrace/android/embracesdk/internal/comms/api/CachedConfig.kt
+++ /dev/null
@@ -1,10 +0,0 @@
-package io.embrace.android.embracesdk.internal.comms.api
-
-import io.embrace.android.embracesdk.internal.config.remote.RemoteConfig
-
-class CachedConfig(
- val remoteConfig: RemoteConfig? = null,
- val eTag: String? = null,
-) {
- fun isValid(): Boolean = remoteConfig != null && eTag != null
-}
diff --git a/embrace-android-payload/src/main/kotlin/io/embrace/android/embracesdk/internal/comms/api/Endpoint.kt b/embrace-android-payload/src/main/kotlin/io/embrace/android/embracesdk/internal/comms/api/Endpoint.kt
index 30296e0ecc..be2e2c46b4 100644
--- a/embrace-android-payload/src/main/kotlin/io/embrace/android/embracesdk/internal/comms/api/Endpoint.kt
+++ b/embrace-android-payload/src/main/kotlin/io/embrace/android/embracesdk/internal/comms/api/Endpoint.kt
@@ -9,5 +9,6 @@ enum class Endpoint(
) {
LOGS("logs", "v2"),
SESSIONS("spans", "v2"),
- UNKNOWN("unknown", "v1")
+ CONFIG("config", "v2"),
+ UNKNOWN("unknown", "v1"),
}
diff --git a/embrace-android-payload/src/main/kotlin/io/embrace/android/embracesdk/internal/config/instrumented/InstrumentedConfig.kt b/embrace-android-payload/src/main/kotlin/io/embrace/android/embracesdk/internal/config/instrumented/InstrumentedConfig.kt
deleted file mode 100644
index a0fbdcfa09..0000000000
--- a/embrace-android-payload/src/main/kotlin/io/embrace/android/embracesdk/internal/config/instrumented/InstrumentedConfig.kt
+++ /dev/null
@@ -1,21 +0,0 @@
-package io.embrace.android.embracesdk.internal.config.instrumented
-
-/**
- * This class and its contents are instrumented by the swazzler to alter its return values
- * based on what values have been set in the embrace-config.json. If no value has been set,
- * the default value specified in the class will be used.
- *
- * It's important to:
- *
- * (1) always use functions, as this is somewhat easier to instrument than Kotlin properties
- * (2) always keep the swazzler in sync when adding new config values or altering existing ones
- */
-@Swazzled
-object InstrumentedConfig {
- val baseUrls: BaseUrlConfig = BaseUrlConfig
- val enabledFeatures: EnabledFeatureConfig = EnabledFeatureConfig
- val networkCapture: NetworkCaptureConfig = NetworkCaptureConfig
- val project: ProjectConfig = ProjectConfig
- val redaction: RedactionConfig = RedactionConfig
- val session: SessionConfig = SessionConfig
-}
diff --git a/embrace-android-payload/src/main/kotlin/io/embrace/android/embracesdk/internal/config/instrumented/InstrumentedConfigImpl.kt b/embrace-android-payload/src/main/kotlin/io/embrace/android/embracesdk/internal/config/instrumented/InstrumentedConfigImpl.kt
new file mode 100644
index 0000000000..eed51253eb
--- /dev/null
+++ b/embrace-android-payload/src/main/kotlin/io/embrace/android/embracesdk/internal/config/instrumented/InstrumentedConfigImpl.kt
@@ -0,0 +1,47 @@
+package io.embrace.android.embracesdk.internal.config.instrumented
+
+import io.embrace.android.embracesdk.internal.config.instrumented.schema.BaseUrlConfig
+import io.embrace.android.embracesdk.internal.config.instrumented.schema.EnabledFeatureConfig
+import io.embrace.android.embracesdk.internal.config.instrumented.schema.InstrumentedConfig
+import io.embrace.android.embracesdk.internal.config.instrumented.schema.NetworkCaptureConfig
+import io.embrace.android.embracesdk.internal.config.instrumented.schema.ProjectConfig
+import io.embrace.android.embracesdk.internal.config.instrumented.schema.RedactionConfig
+import io.embrace.android.embracesdk.internal.config.instrumented.schema.SessionConfig
+
+/**
+ * This class and its contents are instrumented by the swazzler to alter its return values
+ * based on what values have been set in the embrace-config.json. If no value has been set,
+ * the default value specified in the class will be used.
+ *
+ * It's important to:
+ *
+ * (1) always use functions, as this is somewhat easier to instrument than Kotlin properties
+ * (2) always keep the swazzler in sync when adding new config values or altering existing ones
+ */
+@Swazzled
+object InstrumentedConfigImpl : InstrumentedConfig {
+ override val baseUrls: BaseUrlConfig = BaseUrlConfigImpl
+ override val enabledFeatures: EnabledFeatureConfig = EnabledFeatureConfigImpl
+ override val networkCapture: NetworkCaptureConfig = NetworkCaptureConfigImpl
+ override val project: ProjectConfig = ProjectConfigImpl
+ override val redaction: RedactionConfig = RedactionConfigImpl
+ override val session: SessionConfig = SessionConfigImpl
+}
+
+@Swazzled
+object BaseUrlConfigImpl : BaseUrlConfig
+
+@Swazzled
+object EnabledFeatureConfigImpl : EnabledFeatureConfig
+
+@Swazzled
+object NetworkCaptureConfigImpl : NetworkCaptureConfig
+
+@Swazzled
+object ProjectConfigImpl : ProjectConfig
+
+@Swazzled
+object RedactionConfigImpl : RedactionConfig
+
+@Swazzled
+object SessionConfigImpl : SessionConfig
diff --git a/embrace-android-payload/src/main/kotlin/io/embrace/android/embracesdk/internal/config/instrumented/BaseUrlConfig.kt b/embrace-android-payload/src/main/kotlin/io/embrace/android/embracesdk/internal/config/instrumented/schema/BaseUrlConfig.kt
similarity index 82%
rename from embrace-android-payload/src/main/kotlin/io/embrace/android/embracesdk/internal/config/instrumented/BaseUrlConfig.kt
rename to embrace-android-payload/src/main/kotlin/io/embrace/android/embracesdk/internal/config/instrumented/schema/BaseUrlConfig.kt
index 6385207e9b..187b8f54d4 100644
--- a/embrace-android-payload/src/main/kotlin/io/embrace/android/embracesdk/internal/config/instrumented/BaseUrlConfig.kt
+++ b/embrace-android-payload/src/main/kotlin/io/embrace/android/embracesdk/internal/config/instrumented/schema/BaseUrlConfig.kt
@@ -1,11 +1,9 @@
-package io.embrace.android.embracesdk.internal.config.instrumented
+package io.embrace.android.embracesdk.internal.config.instrumented.schema
/**
* Declares the base URLs the SDK should use in HTTP requests
*/
-@Suppress("FunctionOnlyReturningConstant")
-@Swazzled
-object BaseUrlConfig {
+interface BaseUrlConfig {
/**
* Config base URL
diff --git a/embrace-android-payload/src/main/kotlin/io/embrace/android/embracesdk/internal/config/instrumented/EnabledFeatureConfig.kt b/embrace-android-payload/src/main/kotlin/io/embrace/android/embracesdk/internal/config/instrumented/schema/EnabledFeatureConfig.kt
similarity index 97%
rename from embrace-android-payload/src/main/kotlin/io/embrace/android/embracesdk/internal/config/instrumented/EnabledFeatureConfig.kt
rename to embrace-android-payload/src/main/kotlin/io/embrace/android/embracesdk/internal/config/instrumented/schema/EnabledFeatureConfig.kt
index bb215b49c8..7ede1a4c4c 100644
--- a/embrace-android-payload/src/main/kotlin/io/embrace/android/embracesdk/internal/config/instrumented/EnabledFeatureConfig.kt
+++ b/embrace-android-payload/src/main/kotlin/io/embrace/android/embracesdk/internal/config/instrumented/schema/EnabledFeatureConfig.kt
@@ -1,11 +1,9 @@
-package io.embrace.android.embracesdk.internal.config.instrumented
+package io.embrace.android.embracesdk.internal.config.instrumented.schema
/**
* Declares what features are enabled/disabled across the entire SDK.
*/
-@Suppress("FunctionOnlyReturningConstant")
-@Swazzled
-object EnabledFeatureConfig {
+interface EnabledFeatureConfig {
/**
* Gates Unity ANR capture.
diff --git a/embrace-android-payload/src/main/kotlin/io/embrace/android/embracesdk/internal/config/instrumented/schema/InstrumentedConfig.kt b/embrace-android-payload/src/main/kotlin/io/embrace/android/embracesdk/internal/config/instrumented/schema/InstrumentedConfig.kt
new file mode 100644
index 0000000000..911040a6b8
--- /dev/null
+++ b/embrace-android-payload/src/main/kotlin/io/embrace/android/embracesdk/internal/config/instrumented/schema/InstrumentedConfig.kt
@@ -0,0 +1,14 @@
+package io.embrace.android.embracesdk.internal.config.instrumented.schema
+
+/**
+ * Defines the locally set configuration for the SDK. This is typically set from embrace-config.json
+ * and instrumented by swazzler, but can be overridden for test purposes.
+ */
+interface InstrumentedConfig {
+ val baseUrls: BaseUrlConfig
+ val enabledFeatures: EnabledFeatureConfig
+ val networkCapture: NetworkCaptureConfig
+ val project: ProjectConfig
+ val redaction: RedactionConfig
+ val session: SessionConfig
+}
diff --git a/embrace-android-payload/src/main/kotlin/io/embrace/android/embracesdk/internal/config/instrumented/NetworkCaptureConfig.kt b/embrace-android-payload/src/main/kotlin/io/embrace/android/embracesdk/internal/config/instrumented/schema/NetworkCaptureConfig.kt
similarity index 95%
rename from embrace-android-payload/src/main/kotlin/io/embrace/android/embracesdk/internal/config/instrumented/NetworkCaptureConfig.kt
rename to embrace-android-payload/src/main/kotlin/io/embrace/android/embracesdk/internal/config/instrumented/schema/NetworkCaptureConfig.kt
index 326ec2c86f..e51306d410 100644
--- a/embrace-android-payload/src/main/kotlin/io/embrace/android/embracesdk/internal/config/instrumented/NetworkCaptureConfig.kt
+++ b/embrace-android-payload/src/main/kotlin/io/embrace/android/embracesdk/internal/config/instrumented/schema/NetworkCaptureConfig.kt
@@ -1,11 +1,10 @@
-package io.embrace.android.embracesdk.internal.config.instrumented
+package io.embrace.android.embracesdk.internal.config.instrumented.schema
/**
* Declares how the SDK should capture network requests
*/
@Suppress("FunctionOnlyReturningConstant")
-@Swazzled
-object NetworkCaptureConfig {
+interface NetworkCaptureConfig {
/**
* The network request capture limit per domain
diff --git a/embrace-android-payload/src/main/kotlin/io/embrace/android/embracesdk/internal/config/instrumented/ProjectConfig.kt b/embrace-android-payload/src/main/kotlin/io/embrace/android/embracesdk/internal/config/instrumented/schema/ProjectConfig.kt
similarity index 91%
rename from embrace-android-payload/src/main/kotlin/io/embrace/android/embracesdk/internal/config/instrumented/ProjectConfig.kt
rename to embrace-android-payload/src/main/kotlin/io/embrace/android/embracesdk/internal/config/instrumented/schema/ProjectConfig.kt
index 51677bbb83..93a24d8592 100644
--- a/embrace-android-payload/src/main/kotlin/io/embrace/android/embracesdk/internal/config/instrumented/ProjectConfig.kt
+++ b/embrace-android-payload/src/main/kotlin/io/embrace/android/embracesdk/internal/config/instrumented/schema/ProjectConfig.kt
@@ -1,11 +1,9 @@
-package io.embrace.android.embracesdk.internal.config.instrumented
+package io.embrace.android.embracesdk.internal.config.instrumented.schema
/**
* Declares metadata about the app project
*/
-@Suppress("FunctionOnlyReturningConstant")
-@Swazzled
-object ProjectConfig {
+interface ProjectConfig {
/**
* The project's appId
diff --git a/embrace-android-payload/src/main/kotlin/io/embrace/android/embracesdk/internal/config/instrumented/RedactionConfig.kt b/embrace-android-payload/src/main/kotlin/io/embrace/android/embracesdk/internal/config/instrumented/schema/RedactionConfig.kt
similarity index 80%
rename from embrace-android-payload/src/main/kotlin/io/embrace/android/embracesdk/internal/config/instrumented/RedactionConfig.kt
rename to embrace-android-payload/src/main/kotlin/io/embrace/android/embracesdk/internal/config/instrumented/schema/RedactionConfig.kt
index 513ffe96f6..7de255e1af 100644
--- a/embrace-android-payload/src/main/kotlin/io/embrace/android/embracesdk/internal/config/instrumented/RedactionConfig.kt
+++ b/embrace-android-payload/src/main/kotlin/io/embrace/android/embracesdk/internal/config/instrumented/schema/RedactionConfig.kt
@@ -1,11 +1,9 @@
-package io.embrace.android.embracesdk.internal.config.instrumented
+package io.embrace.android.embracesdk.internal.config.instrumented.schema
/**
* Declares how the SDK should redact sensitive data
*/
-@Suppress("FunctionOnlyReturningConstant")
-@Swazzled
-object RedactionConfig {
+interface RedactionConfig {
/**
* Provides a list of sensitive keys whose values should be redacted on capture.
diff --git a/embrace-android-payload/src/main/kotlin/io/embrace/android/embracesdk/internal/config/instrumented/SessionConfig.kt b/embrace-android-payload/src/main/kotlin/io/embrace/android/embracesdk/internal/config/instrumented/schema/SessionConfig.kt
similarity index 79%
rename from embrace-android-payload/src/main/kotlin/io/embrace/android/embracesdk/internal/config/instrumented/SessionConfig.kt
rename to embrace-android-payload/src/main/kotlin/io/embrace/android/embracesdk/internal/config/instrumented/schema/SessionConfig.kt
index 7b2575a51b..8f69dabb2b 100644
--- a/embrace-android-payload/src/main/kotlin/io/embrace/android/embracesdk/internal/config/instrumented/SessionConfig.kt
+++ b/embrace-android-payload/src/main/kotlin/io/embrace/android/embracesdk/internal/config/instrumented/schema/SessionConfig.kt
@@ -1,13 +1,9 @@
-package io.embrace.android.embracesdk.internal.config.instrumented
-
-import com.squareup.moshi.Json
+package io.embrace.android.embracesdk.internal.config.instrumented.schema
/**
* Declares metadata about the app project
*/
-@Suppress("FunctionOnlyReturningConstant")
-@Swazzled
-object SessionConfig {
+interface SessionConfig {
/**
* A whitelist of session components (i.e. Breadcrumbs, Session properties, etc) that should be
@@ -16,7 +12,6 @@ object SessionConfig {
*
* sdk_config.session.components
*/
- @Json(name = "components")
fun getSessionComponents(): List? = null
/**
@@ -25,6 +20,5 @@ object SessionConfig {
*
* sdk_config.session.send_full_for
*/
- @Json(name = "send_full_for")
fun getFullSessionEvents(): List = emptyList()
}
diff --git a/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testcases/EmbraceInternalInterfaceTest.kt b/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testcases/EmbraceInternalInterfaceTest.kt
index c54c185289..aa95aa90a3 100644
--- a/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testcases/EmbraceInternalInterfaceTest.kt
+++ b/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testcases/EmbraceInternalInterfaceTest.kt
@@ -7,8 +7,6 @@ import io.embrace.android.embracesdk.LogType
import io.embrace.android.embracesdk.assertions.findEventOfType
import io.embrace.android.embracesdk.assertions.findSessionSpan
import io.embrace.android.embracesdk.assertions.findSpansByName
-import io.embrace.android.embracesdk.fakes.behavior.FakeSdkModeBehavior
-import io.embrace.android.embracesdk.fakes.createNetworkBehavior
import io.embrace.android.embracesdk.internal.EmbraceInternalApi
import io.embrace.android.embracesdk.internal.arch.schema.EmbType
import io.embrace.android.embracesdk.internal.config.remote.NetworkCaptureRuleRemoteConfig
@@ -113,8 +111,6 @@ internal class EmbraceInternalInterfaceTest {
testRule.runTest(
testCaseAction = {
recordSession {
- clock.tick()
- configService.updateListeners()
clock.tick()
EmbraceInternalApi.getInstance().internalInterface.recordCompletedNetworkRequest(
url = URL,
@@ -207,23 +203,18 @@ internal class EmbraceInternalInterfaceTest {
@Test
fun `access check methods work as expected`() {
testRule.runTest(
- setupAction = {
- overriddenConfigService.networkBehavior =
- createNetworkBehavior(remoteCfg = {
- RemoteConfig(
- disabledUrlPatterns = setOf("dontlogmebro.pizza"),
- networkCaptureRules = setOf(
- NetworkCaptureRuleRemoteConfig(
- id = "test",
- duration = 10000,
- method = "GET",
- urlRegex = "capture.me",
- expiresIn = 10000
- )
- )
- )
- })
- },
+ persistedRemoteConfig = RemoteConfig(
+ disabledUrlPatterns = setOf("dontlogmebro.pizza"),
+ networkCaptureRules = setOf(
+ NetworkCaptureRuleRemoteConfig(
+ id = "test",
+ duration = 10000,
+ method = "GET",
+ urlRegex = "capture.me",
+ expiresIn = 10000
+ )
+ )
+ ),
testCaseAction = {
recordSession {
assertTrue(
@@ -239,7 +230,7 @@ internal class EmbraceInternalInterfaceTest {
)
)
assertFalse(EmbraceInternalApi.getInstance().internalInterface.shouldCaptureNetworkBody(URL, "GET"))
- assertTrue(EmbraceInternalApi.getInstance().internalInterface.isNetworkSpanForwardingEnabled())
+ assertFalse(EmbraceInternalApi.getInstance().internalInterface.isNetworkSpanForwardingEnabled())
}
}
)
@@ -314,10 +305,8 @@ internal class EmbraceInternalInterfaceTest {
@Test
fun `SDK will not start if feature flag has it being disabled`() {
testRule.runTest(
+ persistedRemoteConfig = RemoteConfig(threshold = 0),
expectSdkToStart = false,
- setupAction = {
- overriddenConfigService.sdkModeBehavior = FakeSdkModeBehavior(sdkDisabled = true)
- },
testCaseAction = {
assertFalse(embrace.isStarted)
}
diff --git a/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testcases/FlutterInternalInterfaceTest.kt b/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testcases/FlutterInternalInterfaceTest.kt
index b9ce27625d..0747068f44 100644
--- a/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testcases/FlutterInternalInterfaceTest.kt
+++ b/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testcases/FlutterInternalInterfaceTest.kt
@@ -1,11 +1,10 @@
-@file:Suppress("DEPRECATION")
-
package io.embrace.android.embracesdk.testcases
import androidx.test.ext.junit.runners.AndroidJUnit4
-import io.embrace.android.embracesdk.AppFramework.FLUTTER
import io.embrace.android.embracesdk.LogExceptionType
import io.embrace.android.embracesdk.fakes.FakeClock
+import io.embrace.android.embracesdk.fakes.config.FakeInstrumentedConfig
+import io.embrace.android.embracesdk.fakes.config.FakeProjectConfig
import io.embrace.android.embracesdk.fakes.injection.FakeInitModule
import io.embrace.android.embracesdk.fakes.injection.FakeWorkerThreadModule
import io.embrace.android.embracesdk.internal.EmbraceInternalApi
@@ -30,13 +29,17 @@ import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
internal class FlutterInternalInterfaceTest {
+ private val instrumentedConfig = FakeInstrumentedConfig(project = FakeProjectConfig(
+ appId = "abcde",
+ appFramework = "flutter"
+ ))
+
@Rule
@JvmField
val testRule: IntegrationTestRule = IntegrationTestRule {
val clock = FakeClock(IntegrationTestRule.DEFAULT_SDK_START_TIME_MS)
val fakeInitModule = FakeInitModule(clock = clock)
EmbraceSetupInterface(
- appFramework = FLUTTER,
overriddenClock = clock,
overriddenInitModule = fakeInitModule,
overriddenWorkerThreadModule = FakeWorkerThreadModule(
@@ -49,6 +52,7 @@ internal class FlutterInternalInterfaceTest {
@Test
fun `flutter without values should return defaults`() {
testRule.runTest(
+ instrumentedConfig = instrumentedConfig,
testCaseAction = {
recordSession()
},
@@ -65,6 +69,7 @@ internal class FlutterInternalInterfaceTest {
@Test
fun `flutter methods work in current session`() {
testRule.runTest(
+ instrumentedConfig = instrumentedConfig,
testCaseAction = {
recordSession {
EmbraceInternalApi.getInstance().flutterInternalInterface.setDartVersion("28.9.1")
@@ -84,6 +89,7 @@ internal class FlutterInternalInterfaceTest {
@Test
fun `flutter metadata already present from previous session`() {
testRule.runTest(
+ instrumentedConfig = instrumentedConfig,
testCaseAction = {
recordSession {
EmbraceInternalApi.getInstance().flutterInternalInterface.setDartVersion("28.9.1")
@@ -104,6 +110,7 @@ internal class FlutterInternalInterfaceTest {
@Test
fun `setting null is ignored`() {
testRule.runTest(
+ instrumentedConfig = instrumentedConfig,
testCaseAction = {
recordSession {
EmbraceInternalApi.getInstance().flutterInternalInterface.setDartVersion("28.9.1")
@@ -128,6 +135,7 @@ internal class FlutterInternalInterfaceTest {
@Test
fun `flutter values from current session override previous values`() {
testRule.runTest(
+ instrumentedConfig = instrumentedConfig,
testCaseAction = {
recordSession {
EmbraceInternalApi.getInstance().flutterInternalInterface.setDartVersion("28.9.1")
@@ -158,6 +166,7 @@ internal class FlutterInternalInterfaceTest {
val expectedLibrary = "library"
testRule.runTest(
+ instrumentedConfig = instrumentedConfig,
testCaseAction = {
recordSession {
EmbraceInternalApi.getInstance().flutterInternalInterface.logHandledDartException(
@@ -202,6 +211,7 @@ internal class FlutterInternalInterfaceTest {
val expectedLibrary = "library"
testRule.runTest(
+ instrumentedConfig = instrumentedConfig,
testCaseAction = {
recordSession {
EmbraceInternalApi.getInstance().flutterInternalInterface.logUnhandledDartException(
diff --git a/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testcases/NetworkRequestApiTest.kt b/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testcases/NetworkRequestApiTest.kt
index ab0ee9df8c..59a3087d59 100644
--- a/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testcases/NetworkRequestApiTest.kt
+++ b/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testcases/NetworkRequestApiTest.kt
@@ -1,7 +1,6 @@
package io.embrace.android.embracesdk.testcases
import androidx.test.ext.junit.runners.AndroidJUnit4
-import io.embrace.android.embracesdk.fakes.createNetworkBehavior
import io.embrace.android.embracesdk.internal.clock.millisToNanos
import io.embrace.android.embracesdk.internal.config.remote.NetworkCaptureRuleRemoteConfig
import io.embrace.android.embracesdk.internal.config.remote.RemoteConfig
@@ -180,26 +179,20 @@ internal class NetworkRequestApiTest {
@Test
fun `disabled URLs not recorded`() {
testRule.runTest(
- setupAction = {
- overriddenConfigService.networkBehavior =
- createNetworkBehavior(remoteCfg = {
- RemoteConfig(
- disabledUrlPatterns = setOf("dontlogmebro.pizza"),
- networkCaptureRules = setOf(
- NetworkCaptureRuleRemoteConfig(
- id = "test",
- duration = 10000,
- method = "GET",
- urlRegex = "capture.me",
- expiresIn = 10000
- )
- )
- )
- })
- },
+ persistedRemoteConfig = RemoteConfig(
+ disabledUrlPatterns = setOf("dontlogmebro.pizza"),
+ networkCaptureRules = setOf(
+ NetworkCaptureRuleRemoteConfig(
+ id = "test",
+ duration = 10000,
+ method = "GET",
+ urlRegex = "capture.me",
+ expiresIn = 10000
+ )
+ )
+ ),
testCaseAction = {
recordSession {
- configService.updateListeners()
clock.tick(5)
embrace.recordNetworkRequest(
EmbraceNetworkRequest.fromCompletedRequest(
@@ -253,7 +246,6 @@ internal class NetworkRequestApiTest {
testRule.runTest(
testCaseAction = {
recordSession {
- configService.updateListeners()
clock.tick(5)
val request = EmbraceNetworkRequest.fromCompletedRequest(
@@ -292,7 +284,6 @@ internal class NetworkRequestApiTest {
testCaseAction = {
recordSession {
clock.tick(2L)
- configService.updateListeners()
clock.tick(5L)
embrace.recordNetworkRequest(expectedRequest)
}
diff --git a/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testcases/PublicApiTest.kt b/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testcases/PublicApiTest.kt
index 440f82ff68..0470220368 100644
--- a/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testcases/PublicApiTest.kt
+++ b/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testcases/PublicApiTest.kt
@@ -2,12 +2,12 @@ package io.embrace.android.embracesdk.testcases
import androidx.test.ext.junit.runners.AndroidJUnit4
import io.embrace.android.embracesdk.LastRunEndState
-import io.embrace.android.embracesdk.fakes.behavior.FakeNetworkSpanForwardingBehavior
-import io.embrace.android.embracesdk.internal.payload.AppFramework
+import io.embrace.android.embracesdk.fakes.config.FakeEnabledFeatureConfig
+import io.embrace.android.embracesdk.fakes.config.FakeInstrumentedConfig
+import io.embrace.android.embracesdk.internal.config.remote.BackgroundActivityRemoteConfig
+import io.embrace.android.embracesdk.internal.config.remote.RemoteConfig
import io.embrace.android.embracesdk.testframework.IntegrationTestRule
-import io.embrace.android.embracesdk.testframework.actions.EmbraceSetupInterface
import org.junit.Assert.assertEquals
-import org.junit.Assert.assertFalse
import org.junit.Assert.assertNotEquals
import org.junit.Assert.assertNotNull
import org.junit.Assert.assertNull
@@ -26,55 +26,26 @@ internal class PublicApiTest {
val validPattern = Regex("^00-" + "[0-9a-fA-F]{32}" + "-" + "[0-9a-fA-F]{16}" + "-01$")
}
+ private val instrumentedConfig = FakeInstrumentedConfig(enabledFeatures = FakeEnabledFeatureConfig(networkSpanForwarding = true))
+
@Rule
@JvmField
- val testRule: IntegrationTestRule = IntegrationTestRule {
- EmbraceSetupInterface().apply {
- overriddenConfigService.networkSpanForwardingBehavior =
- FakeNetworkSpanForwardingBehavior(true)
- }
- }
-
- @Test
- fun `SDK can start`() {
- testRule.runTest(
- preSdkStartAction = {
- assertFalse(embrace.isStarted)
- },
- testCaseAction = {
- assertEquals(AppFramework.NATIVE, configService.appFramework)
- assertFalse(configService.isSdkDisabled())
- assertTrue(embrace.isStarted)
- }
- )
- }
+ val testRule: IntegrationTestRule = IntegrationTestRule()
@Test
fun `SDK start defaults to native app framework`() {
testRule.runTest(
+ instrumentedConfig = instrumentedConfig,
testCaseAction = {
- assertEquals(AppFramework.NATIVE, configService.appFramework)
assertTrue(embrace.isStarted)
}
)
}
- @Test
- fun `SDK disabled via config cannot start`() {
- testRule.runTest(
- expectSdkToStart = false,
- setupAction = {
- overriddenConfigService.sdkDisabled = true
- },
- testCaseAction = {
- assertFalse(embrace.isStarted)
- }
- )
- }
-
@Test
fun `getCurrentSessionId returns null when SDK is not started`() {
testRule.runTest(
+ instrumentedConfig = instrumentedConfig,
startSdk = false,
testCaseAction = {
assertNull(embrace.currentSessionId)
@@ -85,6 +56,7 @@ internal class PublicApiTest {
@Test
fun `getCurrentSessionId returns sessionId when SDK is started and foreground session is active`() {
testRule.runTest(
+ instrumentedConfig = instrumentedConfig,
testCaseAction = {
recordSession {
assertEquals(
@@ -102,6 +74,8 @@ internal class PublicApiTest {
var foregroundSessionId: String? = null
var backgroundSessionId: String? = null
testRule.runTest(
+ persistedRemoteConfig = RemoteConfig(backgroundActivityConfig = BackgroundActivityRemoteConfig(100f)),
+ instrumentedConfig = instrumentedConfig,
testCaseAction = {
recordSession {
foregroundSessionId = embrace.currentSessionId
@@ -118,6 +92,7 @@ internal class PublicApiTest {
@Test
fun `getLastRunEndState() behave as expected`() {
testRule.runTest(
+ instrumentedConfig = instrumentedConfig,
preSdkStartAction = {
assertEquals(LastRunEndState.INVALID, embrace.lastRunEndState)
},
@@ -130,6 +105,7 @@ internal class PublicApiTest {
@Test
fun `ensure all generated W3C traceparent conforms to the expected format`() {
testRule.runTest(
+ instrumentedConfig = instrumentedConfig,
testCaseAction = {
repeat(100) {
assertTrue(validPattern.matches(checkNotNull(embrace.generateW3cTraceparent())))
diff --git a/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testcases/PushNotificationApiTest.kt b/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testcases/PushNotificationApiTest.kt
index 6472060b28..65858c0fc4 100644
--- a/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testcases/PushNotificationApiTest.kt
+++ b/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testcases/PushNotificationApiTest.kt
@@ -3,7 +3,8 @@ package io.embrace.android.embracesdk.testcases
import androidx.test.ext.junit.runners.AndroidJUnit4
import io.embrace.android.embracesdk.assertions.findEventOfType
import io.embrace.android.embracesdk.assertions.findSessionSpan
-import io.embrace.android.embracesdk.fakes.FakeBreadcrumbBehavior
+import io.embrace.android.embracesdk.fakes.config.FakeEnabledFeatureConfig
+import io.embrace.android.embracesdk.fakes.config.FakeInstrumentedConfig
import io.embrace.android.embracesdk.internal.arch.schema.EmbType
import io.embrace.android.embracesdk.internal.payload.Envelope
import io.embrace.android.embracesdk.internal.payload.SessionPayload
@@ -84,11 +85,9 @@ internal class PushNotificationApiTest {
@Test
fun `log push notification with pii`() {
testRule.runTest(
- setupAction = {
- overriddenConfigService.breadcrumbBehavior = FakeBreadcrumbBehavior(
- captureFcmPiiDataEnabled = true
- )
- },
+ instrumentedConfig = FakeInstrumentedConfig(
+ enabledFeatures = FakeEnabledFeatureConfig(fcmPiiCapture = true),
+ ),
testCaseAction = {
recordSession {
embrace.logPushNotification("title", "body", "from", "id", 1, 2, true, true)
diff --git a/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testcases/ReactNativeInternalInterfaceTest.kt b/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testcases/ReactNativeInternalInterfaceTest.kt
index f51582828e..e8af191bfd 100644
--- a/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testcases/ReactNativeInternalInterfaceTest.kt
+++ b/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testcases/ReactNativeInternalInterfaceTest.kt
@@ -1,12 +1,11 @@
-@file:Suppress("DEPRECATION")
-
package io.embrace.android.embracesdk.testcases
import androidx.test.ext.junit.runners.AndroidJUnit4
-import io.embrace.android.embracesdk.AppFramework.REACT_NATIVE
import io.embrace.android.embracesdk.assertions.findSpanOfType
import io.embrace.android.embracesdk.assertions.findSpanSnapshotOfType
import io.embrace.android.embracesdk.assertions.findSpansByName
+import io.embrace.android.embracesdk.fakes.config.FakeInstrumentedConfig
+import io.embrace.android.embracesdk.fakes.config.FakeProjectConfig
import io.embrace.android.embracesdk.internal.EmbraceInternalApi
import io.embrace.android.embracesdk.internal.arch.schema.EmbType
import io.embrace.android.embracesdk.internal.clock.nanosToMillis
@@ -26,15 +25,19 @@ import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
internal class ReactNativeInternalInterfaceTest {
+ private val instrumentedConfig = FakeInstrumentedConfig(project = FakeProjectConfig(
+ appId = "abcde",
+ appFramework = "react_native"
+ ))
+
@Rule
@JvmField
- val testRule: IntegrationTestRule = IntegrationTestRule {
- EmbraceSetupInterface(appFramework = REACT_NATIVE)
- }
+ val testRule: IntegrationTestRule = IntegrationTestRule()
@Test
fun `react native without values should return defaults`() {
testRule.runTest(
+ instrumentedConfig = instrumentedConfig,
testCaseAction = {
recordSession()
},
@@ -51,6 +54,7 @@ internal class ReactNativeInternalInterfaceTest {
@Test
fun `react native methods work in current session`() {
testRule.runTest(
+ instrumentedConfig = instrumentedConfig,
testCaseAction = {
recordSession {
EmbraceInternalApi.getInstance().reactNativeInternalInterface.setReactNativeVersionNumber("28.9.1")
@@ -72,6 +76,7 @@ internal class ReactNativeInternalInterfaceTest {
@Test
fun `react native metadata already present from previous session`() {
testRule.runTest(
+ instrumentedConfig = instrumentedConfig,
testCaseAction = {
recordSession {
EmbraceInternalApi.getInstance().reactNativeInternalInterface.setReactNativeVersionNumber("28.9.1")
@@ -95,6 +100,7 @@ internal class ReactNativeInternalInterfaceTest {
@Test
fun `react native values from current session override previous values`() {
testRule.runTest(
+ instrumentedConfig = instrumentedConfig,
testCaseAction = {
recordSession {
EmbraceInternalApi.getInstance().reactNativeInternalInterface.setReactNativeVersionNumber("28.9.1")
@@ -123,6 +129,7 @@ internal class ReactNativeInternalInterfaceTest {
@Test
fun `react native action`() {
testRule.runTest(
+ instrumentedConfig = instrumentedConfig,
testCaseAction = {
recordSession {
EmbraceInternalApi.getInstance().reactNativeInternalInterface.logRnAction(
@@ -163,6 +170,7 @@ internal class ReactNativeInternalInterfaceTest {
@Test
fun `react native log RN view`() {
testRule.runTest(
+ instrumentedConfig = instrumentedConfig,
testCaseAction = {
recordSession {
EmbraceInternalApi.getInstance().reactNativeInternalInterface.logRnView("HomeScreen")
@@ -197,6 +205,7 @@ internal class ReactNativeInternalInterfaceTest {
@Test
fun `react native log RN view same name`() {
testRule.runTest(
+ instrumentedConfig = instrumentedConfig,
testCaseAction = {
recordSession {
EmbraceInternalApi.getInstance().reactNativeInternalInterface.logRnView("HomeScreen")
diff --git a/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testcases/SessionApiTest.kt b/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testcases/SessionApiTest.kt
index d98371c4b4..8f1b716641 100644
--- a/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testcases/SessionApiTest.kt
+++ b/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testcases/SessionApiTest.kt
@@ -3,6 +3,8 @@ package io.embrace.android.embracesdk.testcases
import androidx.test.ext.junit.runners.AndroidJUnit4
import io.embrace.android.embracesdk.ResourceReader
import io.embrace.android.embracesdk.fakes.behavior.FakeAutoDataCaptureBehavior
+import io.embrace.android.embracesdk.fakes.config.FakeEnabledFeatureConfig
+import io.embrace.android.embracesdk.fakes.config.FakeInstrumentedConfig
import io.embrace.android.embracesdk.internal.clock.millisToNanos
import io.embrace.android.embracesdk.internal.clock.nanosToMillis
import io.embrace.android.embracesdk.internal.opentelemetry.embFreeDiskBytes
@@ -23,12 +25,7 @@ internal class SessionApiTest {
@Rule
@JvmField
- val testRule: IntegrationTestRule = IntegrationTestRule {
- EmbraceSetupInterface().apply {
- overriddenConfigService.autoDataCaptureBehavior =
- FakeAutoDataCaptureBehavior(diskUsageReportingEnabled = false)
- }
- }
+ val testRule: IntegrationTestRule = IntegrationTestRule()
/**
* Verifies that a session end message is sent.
@@ -39,6 +36,7 @@ internal class SessionApiTest {
var startTime: Long = -1
testRule.runTest(
+ instrumentedConfig = FakeInstrumentedConfig(enabledFeatures = FakeEnabledFeatureConfig(diskUsageCapture = false, bgActivityCapture = true)),
testCaseAction = {
startTime = clock.now()
recordSession {
diff --git a/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testcases/TracingApiTest.kt b/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testcases/TracingApiTest.kt
index 0a6fb25a0e..b55fbb5613 100644
--- a/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testcases/TracingApiTest.kt
+++ b/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testcases/TracingApiTest.kt
@@ -5,10 +5,14 @@ import io.embrace.android.embracesdk.arch.assertIsTypePerformance
import io.embrace.android.embracesdk.assertions.assertEmbraceSpanData
import io.embrace.android.embracesdk.concurrency.SingleThreadTestScheduledExecutor
import io.embrace.android.embracesdk.fakes.FakeSpanExporter
+import io.embrace.android.embracesdk.fakes.config.FakeEnabledFeatureConfig
+import io.embrace.android.embracesdk.fakes.config.FakeInstrumentedConfig
+import io.embrace.android.embracesdk.fakes.createBackgroundActivityBehavior
import io.embrace.android.embracesdk.fixtures.TOO_LONG_ATTRIBUTE_KEY
import io.embrace.android.embracesdk.fixtures.TOO_LONG_ATTRIBUTE_VALUE
import io.embrace.android.embracesdk.internal.EmbraceInternalApi
import io.embrace.android.embracesdk.internal.clock.millisToNanos
+import io.embrace.android.embracesdk.internal.config.remote.BackgroundActivityRemoteConfig
import io.embrace.android.embracesdk.internal.payload.ApplicationState
import io.embrace.android.embracesdk.internal.payload.Attribute
import io.embrace.android.embracesdk.internal.payload.Span
@@ -56,6 +60,7 @@ internal class TracingApiTest {
val spanExporter = FakeSpanExporter()
testRule.runTest(
+ instrumentedConfig = FakeInstrumentedConfig(enabledFeatures = FakeEnabledFeatureConfig(bgActivityCapture = true)),
preSdkStartAction = {
testStartTimeMs = clock.now()
clock.tick(100L)
@@ -320,9 +325,6 @@ internal class TracingApiTest {
@Test
fun `can only create span if there is a valid session`() {
testRule.runTest(
- setupAction = {
- overriddenConfigService.backgroundActivityCaptureEnabled = false
- },
preSdkStartAction = {
assertNull(embrace.startSpan("test"))
},
diff --git a/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testcases/UnityInternalInterfaceTest.kt b/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testcases/UnityInternalInterfaceTest.kt
index 029b6d7612..874008e65f 100644
--- a/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testcases/UnityInternalInterfaceTest.kt
+++ b/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testcases/UnityInternalInterfaceTest.kt
@@ -1,13 +1,11 @@
-@file:Suppress("DEPRECATION")
-
package io.embrace.android.embracesdk.testcases
import androidx.test.ext.junit.runners.AndroidJUnit4
-import io.embrace.android.embracesdk.AppFramework.UNITY
+import io.embrace.android.embracesdk.fakes.config.FakeInstrumentedConfig
+import io.embrace.android.embracesdk.fakes.config.FakeProjectConfig
import io.embrace.android.embracesdk.internal.EmbraceInternalApi
import io.embrace.android.embracesdk.internal.payload.AppFramework
import io.embrace.android.embracesdk.testframework.IntegrationTestRule
-import io.embrace.android.embracesdk.testframework.actions.EmbraceSetupInterface
import org.junit.Assert.assertEquals
import org.junit.Assert.assertNull
import org.junit.Rule
@@ -20,15 +18,19 @@ import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
internal class UnityInternalInterfaceTest {
+ private val instrumentedConfig = FakeInstrumentedConfig(project = FakeProjectConfig(
+ appId = "abcde",
+ appFramework = "unity"
+ ))
+
@Rule
@JvmField
- val testRule: IntegrationTestRule = IntegrationTestRule {
- EmbraceSetupInterface(appFramework = UNITY)
- }
+ val testRule: IntegrationTestRule = IntegrationTestRule()
@Test
fun `unity without values should return defaults`() {
testRule.runTest(
+ instrumentedConfig = instrumentedConfig,
testCaseAction = {
recordSession()
},
@@ -45,6 +47,7 @@ internal class UnityInternalInterfaceTest {
@Test
fun `unity methods work in current session`() {
testRule.runTest(
+ instrumentedConfig = instrumentedConfig,
testCaseAction = {
recordSession {
EmbraceInternalApi.getInstance().unityInternalInterface.setUnityMetaData(
@@ -68,6 +71,7 @@ internal class UnityInternalInterfaceTest {
@Test
fun `unity metadata already present from previous session`() {
testRule.runTest(
+ instrumentedConfig = instrumentedConfig,
testCaseAction = {
recordSession {
EmbraceInternalApi.getInstance().unityInternalInterface.setUnityMetaData(
@@ -92,6 +96,7 @@ internal class UnityInternalInterfaceTest {
@Test
fun `unity values from current session override previous values`() {
testRule.runTest(
+ instrumentedConfig = instrumentedConfig,
testCaseAction = {
recordSession {
EmbraceInternalApi.getInstance().unityInternalInterface.setUnityMetaData(
diff --git a/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testcases/features/ActivityFeatureTest.kt b/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testcases/features/ActivityFeatureTest.kt
index ffbda44ee0..16ee1053be 100644
--- a/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testcases/features/ActivityFeatureTest.kt
+++ b/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testcases/features/ActivityFeatureTest.kt
@@ -3,7 +3,6 @@ package io.embrace.android.embracesdk.testcases.features
import android.os.Build
import androidx.test.ext.junit.runners.AndroidJUnit4
import io.embrace.android.embracesdk.assertions.findSpanOfType
-import io.embrace.android.embracesdk.fakes.FakeBreadcrumbBehavior
import io.embrace.android.embracesdk.internal.arch.schema.EmbType
import io.embrace.android.embracesdk.internal.clock.nanosToMillis
import io.embrace.android.embracesdk.testframework.IntegrationTestRule
@@ -27,11 +26,6 @@ internal class ActivityFeatureTest {
var startTimeMs: Long = 0
testRule.runTest(
- setupAction = {
- overriddenConfigService.breadcrumbBehavior = FakeBreadcrumbBehavior(
- automaticActivityCaptureEnabled = true
- )
- },
testCaseAction = {
recordSession {
startTimeMs = clock.now()
diff --git a/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testcases/features/BreadcrumbFeatureTest.kt b/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testcases/features/BreadcrumbFeatureTest.kt
index 92ac750c92..6eb6bcdca1 100644
--- a/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testcases/features/BreadcrumbFeatureTest.kt
+++ b/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testcases/features/BreadcrumbFeatureTest.kt
@@ -4,6 +4,8 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
import io.embrace.android.embracesdk.assertions.findEventOfType
import io.embrace.android.embracesdk.assertions.findSessionSpan
import io.embrace.android.embracesdk.internal.arch.schema.EmbType
+import io.embrace.android.embracesdk.internal.config.remote.BackgroundActivityRemoteConfig
+import io.embrace.android.embracesdk.internal.config.remote.RemoteConfig
import io.embrace.android.embracesdk.internal.payload.ApplicationState
import io.embrace.android.embracesdk.internal.payload.Envelope
import io.embrace.android.embracesdk.internal.payload.SessionPayload
@@ -23,6 +25,7 @@ internal class BreadcrumbFeatureTest {
@Test
fun `custom breadcrumb feature`() {
testRule.runTest(
+ persistedRemoteConfig = RemoteConfig(backgroundActivityConfig = BackgroundActivityRemoteConfig(100f)),
testCaseAction = {
recordSession {
embrace.addBreadcrumb("Hello, world!")
diff --git a/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testcases/features/EmbraceLoggingFeatureTest.kt b/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testcases/features/EmbraceLoggingFeatureTest.kt
index 55b27ff546..70666ce0de 100644
--- a/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testcases/features/EmbraceLoggingFeatureTest.kt
+++ b/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testcases/features/EmbraceLoggingFeatureTest.kt
@@ -4,6 +4,8 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
import io.embrace.android.embracesdk.LogExceptionType
import io.embrace.android.embracesdk.Severity
import io.embrace.android.embracesdk.fakes.FakeClock
+import io.embrace.android.embracesdk.fakes.config.FakeEnabledFeatureConfig
+import io.embrace.android.embracesdk.fakes.config.FakeInstrumentedConfig
import io.embrace.android.embracesdk.fakes.injection.FakeInitModule
import io.embrace.android.embracesdk.fakes.injection.FakeWorkerThreadModule
import io.embrace.android.embracesdk.internal.payload.Envelope
@@ -21,6 +23,8 @@ import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
internal class EmbraceLoggingFeatureTest {
+ private val instrumentedConfig = FakeInstrumentedConfig(enabledFeatures = FakeEnabledFeatureConfig(bgActivityCapture = true))
+
@Rule
@JvmField
val testRule: IntegrationTestRule = IntegrationTestRule {
@@ -39,6 +43,7 @@ internal class EmbraceLoggingFeatureTest {
@Test
fun `log info message sent in foreground`() {
testRule.runTest(
+ instrumentedConfig = instrumentedConfig,
testCaseAction = {
recordSession {
embrace.logInfo("test message")
@@ -61,6 +66,7 @@ internal class EmbraceLoggingFeatureTest {
@Test
fun `log warning message sent in background`() {
testRule.runTest(
+ instrumentedConfig = instrumentedConfig,
testCaseAction = {
embrace.logWarning("test message")
flushLogs()
@@ -80,6 +86,7 @@ internal class EmbraceLoggingFeatureTest {
@Test
fun `log error message sent`() {
testRule.runTest(
+ instrumentedConfig = instrumentedConfig,
testCaseAction = {
embrace.logError("test message")
flushLogs()
@@ -99,6 +106,7 @@ internal class EmbraceLoggingFeatureTest {
@Test
fun `log messages with different severities sent`() {
testRule.runTest(
+ instrumentedConfig = instrumentedConfig,
testCaseAction = {
Severity.values().forEach { severity ->
val expectedMessage = "test message ${severity.name}"
@@ -125,6 +133,7 @@ internal class EmbraceLoggingFeatureTest {
@Test
fun `log messages with different severities and properties sent`() {
testRule.runTest(
+ instrumentedConfig = instrumentedConfig,
testCaseAction = {
Severity.values().forEach { severity ->
val expectedMessage = "test message ${severity.name}"
@@ -151,6 +160,7 @@ internal class EmbraceLoggingFeatureTest {
@Test
fun `log exception message sent`() {
testRule.runTest(
+ instrumentedConfig = instrumentedConfig,
testCaseAction = {
embrace.logException(testException)
flushLogs()
@@ -175,6 +185,7 @@ internal class EmbraceLoggingFeatureTest {
@Test
fun `log exception with different severities sent`() {
testRule.runTest(
+ instrumentedConfig = instrumentedConfig,
testCaseAction = {
embrace.logException(testException, Severity.INFO)
flushLogs()
@@ -199,6 +210,7 @@ internal class EmbraceLoggingFeatureTest {
@Test
fun `log exception with different severities and properties sent`() {
testRule.runTest(
+ instrumentedConfig = instrumentedConfig,
testCaseAction = {
Severity.values().forEach { severity ->
embrace.logException(
@@ -232,6 +244,7 @@ internal class EmbraceLoggingFeatureTest {
@Test
fun `log exception with different severities, properties, and custom message sent`() {
testRule.runTest(
+ instrumentedConfig = instrumentedConfig,
testCaseAction = {
Severity.values().forEach { severity ->
val expectedMessage = "test message ${severity.name}"
@@ -264,6 +277,7 @@ internal class EmbraceLoggingFeatureTest {
@Test
fun `log custom stacktrace message sent`() {
testRule.runTest(
+ instrumentedConfig = instrumentedConfig,
testCaseAction = {
embrace.logCustomStacktrace(stacktrace)
flushLogs()
@@ -286,6 +300,7 @@ internal class EmbraceLoggingFeatureTest {
@Test
fun `log custom stacktrace with different severities sent`() {
testRule.runTest(
+ instrumentedConfig = instrumentedConfig,
testCaseAction = {
Severity.values().forEach { severity ->
embrace.logCustomStacktrace(stacktrace, severity)
@@ -313,6 +328,7 @@ internal class EmbraceLoggingFeatureTest {
@Test
fun `log custom stacktrace with different severities and properties sent`() {
testRule.runTest(
+ instrumentedConfig = instrumentedConfig,
testCaseAction = {
Severity.values().forEach { severity ->
embrace.logCustomStacktrace(stacktrace, severity, customProperties)
@@ -341,6 +357,7 @@ internal class EmbraceLoggingFeatureTest {
@Test
fun `log custom stacktrace with different severities, properties, and custom message sent`() {
testRule.runTest(
+ instrumentedConfig = instrumentedConfig,
testCaseAction = {
Severity.values().forEach { severity ->
val expectedMessage = "test message ${severity.name}"
diff --git a/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testcases/features/JvmCrashFeatureTest.kt b/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testcases/features/JvmCrashFeatureTest.kt
index 8a7c369948..9c0d21806d 100644
--- a/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testcases/features/JvmCrashFeatureTest.kt
+++ b/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testcases/features/JvmCrashFeatureTest.kt
@@ -1,10 +1,13 @@
package io.embrace.android.embracesdk.testcases.features
import androidx.test.ext.junit.runners.AndroidJUnit4
+import io.embrace.android.embracesdk.fakes.config.FakeInstrumentedConfig
+import io.embrace.android.embracesdk.fakes.config.FakeProjectConfig
import io.embrace.android.embracesdk.internal.EmbraceInternalApi
+import io.embrace.android.embracesdk.internal.config.remote.BackgroundActivityRemoteConfig
+import io.embrace.android.embracesdk.internal.config.remote.RemoteConfig
import io.embrace.android.embracesdk.internal.opentelemetry.embCrashId
import io.embrace.android.embracesdk.internal.opentelemetry.embState
-import io.embrace.android.embracesdk.internal.payload.AppFramework
import io.embrace.android.embracesdk.internal.payload.ApplicationState
import io.embrace.android.embracesdk.internal.payload.Envelope
import io.embrace.android.embracesdk.internal.payload.LegacyExceptionInfo
@@ -59,6 +62,7 @@ internal class JvmCrashFeatureTest {
@Test
fun `app crash in the background generates a crash log`() {
testRule.runTest(
+ persistedRemoteConfig = RemoteConfig(backgroundActivityConfig = BackgroundActivityRemoteConfig(100f)),
testCaseAction = {
simulateJvmUncaughtException(testException)
},
@@ -72,13 +76,15 @@ internal class JvmCrashFeatureTest {
)
}
- @Suppress("DEPRECATION")
@Test
fun `React Native crash generates an OTel Log and matches the crashId in the session`() {
testRule.runTest(
- setupAction = {
- overriddenConfigService.appFramework = AppFramework.REACT_NATIVE
- },
+ instrumentedConfig = FakeInstrumentedConfig(
+ project = FakeProjectConfig(
+ appId = "abcde",
+ appFramework = "react_native"
+ )
+ ),
testCaseAction = {
recordSession {
EmbraceInternalApi.getInstance().reactNativeInternalInterface.logUnhandledJsException(
diff --git a/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testcases/features/PruningFeatureTest.kt b/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testcases/features/PruningFeatureTest.kt
index 191648bd9e..1937446427 100644
--- a/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testcases/features/PruningFeatureTest.kt
+++ b/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testcases/features/PruningFeatureTest.kt
@@ -40,9 +40,6 @@ internal class PruningFeatureTest {
@Test
fun `stored payloads are pruned appropriately`() {
testRule.runTest(
- setupAction = {
- overriddenConfigService.backgroundActivityCaptureEnabled = false
- },
testCaseAction = {
simulateNetworkChange(NetworkStatus.NOT_REACHABLE)
repeat(STORAGE_LIMIT + OVERAGE) { k ->
diff --git a/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testcases/features/RemoteConfigTest.kt b/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testcases/features/RemoteConfigTest.kt
new file mode 100644
index 0000000000..da0f5e808b
--- /dev/null
+++ b/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testcases/features/RemoteConfigTest.kt
@@ -0,0 +1,73 @@
+package io.embrace.android.embracesdk.testcases.features
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import io.embrace.android.embracesdk.assertions.returnIfConditionMet
+import io.embrace.android.embracesdk.internal.config.remote.RemoteConfig
+import io.embrace.android.embracesdk.testframework.IntegrationTestRule
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertFalse
+import org.junit.Assert.assertTrue
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+/**
+ * Tests how the SDK behaves when controlling by 'remote config'. This is a HTTP response from the
+ * Embrace server that can enable or disable individual features or the entire SDK.
+ */
+@RunWith(AndroidJUnit4::class)
+internal class RemoteConfigTest {
+
+ private val sdkDisabledConfig = RemoteConfig(0)
+ private val sdkEnabledConfig = RemoteConfig(100)
+
+ @Rule
+ @JvmField
+ val testRule: IntegrationTestRule = IntegrationTestRule()
+
+ @Test
+ fun `SDK can start`() {
+ testRule.runTest(
+ persistedRemoteConfig = sdkEnabledConfig,
+ preSdkStartAction = {
+ assertNoConfigPersisted()
+ assertFalse(embrace.isStarted)
+ },
+ testCaseAction = {
+ assertTrue(embrace.isStarted)
+ },
+ assertAction = {
+ assertConfigRequested(1)
+ val response = readPersistedConfigResponse()
+ assertEquals(100, response.cfg?.threshold)
+ assertEquals("server_etag_value", response.etag)
+ }
+ )
+ }
+
+ @Test
+ fun `SDK disabled via config cannot start`() {
+ testRule.runTest(
+ persistedRemoteConfig = sdkDisabledConfig,
+ serverResponseConfig = sdkEnabledConfig,
+ expectSdkToStart = false,
+ preSdkStartAction = {
+ assertNoConfigPersisted()
+ },
+ testCaseAction = {
+ assertFalse(embrace.isStarted)
+ },
+ assertAction = {
+ assertConfigRequested(1)
+ returnIfConditionMet(
+ dataProvider = ::readPersistedConfigResponse,
+ condition = {
+ val response = readPersistedConfigResponse()
+ response.cfg?.threshold == 100 && response.etag == "server_etag_value"
+ },
+ desiredValueSupplier = {}
+ )
+ }
+ )
+ }
+}
diff --git a/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testcases/features/ResurrectionFeatureTest.kt b/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testcases/features/ResurrectionFeatureTest.kt
index a7a0e92ae0..d567b7911b 100644
--- a/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testcases/features/ResurrectionFeatureTest.kt
+++ b/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testcases/features/ResurrectionFeatureTest.kt
@@ -4,10 +4,11 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
import io.embrace.android.embracesdk.assertions.getSessionId
import io.embrace.android.embracesdk.fakes.FakeNativeCrashService
import io.embrace.android.embracesdk.fakes.FakePayloadStorageService
-import io.embrace.android.embracesdk.fakes.behavior.FakeAutoDataCaptureBehavior
import io.embrace.android.embracesdk.fakes.fakeIncompleteSessionEnvelope
import io.embrace.android.embracesdk.fixtures.fakeCachedSessionStoredTelemetryMetadata
import io.embrace.android.embracesdk.internal.clock.nanosToMillis
+import io.embrace.android.embracesdk.internal.config.remote.KillSwitchRemoteConfig
+import io.embrace.android.embracesdk.internal.config.remote.RemoteConfig
import io.embrace.android.embracesdk.internal.opentelemetry.embCrashId
import io.embrace.android.embracesdk.internal.payload.NativeCrashData
import io.embrace.android.embracesdk.internal.payload.Span
@@ -45,9 +46,6 @@ internal class ResurrectionFeatureTest {
)
testRule.runTest(
setupAction = {
- overriddenConfigService.autoDataCaptureBehavior = FakeAutoDataCaptureBehavior(
- v2StorageEnabled = true
- )
cacheStorageService.addPayload(sessionMetadata, deadSessionEnvelope)
cacheStorageServiceProvider = { cacheStorageService }
val nativeCrashService = fakeNativeFeatureModule.nativeCrashService as FakeNativeCrashService
@@ -84,11 +82,9 @@ internal class ResurrectionFeatureTest {
@Test
fun `resurrection attempt with v2 delivery layer off does not crash the SDK`() {
testRule.runTest(
+ persistedRemoteConfig = RemoteConfig(killSwitchConfig = KillSwitchRemoteConfig(v2StoragePct = 0f)),
setupAction = {
useMockWebServer = false
- overriddenConfigService.autoDataCaptureBehavior = FakeAutoDataCaptureBehavior(
- v2StorageEnabled = false
- )
},
testCaseAction = {
recordSession()
diff --git a/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testcases/features/SensitiveKeysRedactionFeatureTest.kt b/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testcases/features/SensitiveKeysRedactionFeatureTest.kt
index dcbef06937..ab8b057587 100644
--- a/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testcases/features/SensitiveKeysRedactionFeatureTest.kt
+++ b/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testcases/features/SensitiveKeysRedactionFeatureTest.kt
@@ -2,8 +2,9 @@ package io.embrace.android.embracesdk.testcases.features
import androidx.test.ext.junit.runners.AndroidJUnit4
import io.embrace.android.embracesdk.assertions.findSpanByName
+import io.embrace.android.embracesdk.fakes.config.FakeInstrumentedConfig
+import io.embrace.android.embracesdk.fakes.config.FakeRedactionConfig
import io.embrace.android.embracesdk.internal.config.behavior.REDACTED_LABEL
-import io.embrace.android.embracesdk.internal.config.behavior.SensitiveKeysBehaviorImpl
import io.embrace.android.embracesdk.testframework.IntegrationTestRule
import io.embrace.android.embracesdk.testframework.assertions.assertMatches
import org.junit.Rule
@@ -12,20 +13,19 @@ import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
internal class SensitiveKeysRedactionFeatureTest {
+
+ private val instrumentedConfig = FakeInstrumentedConfig(
+ redaction = FakeRedactionConfig(sensitiveKeys = listOf("password"))
+ )
+
@Rule
@JvmField
val testRule: IntegrationTestRule = IntegrationTestRule()
- private val sensitiveKeysBehavior = SensitiveKeysBehaviorImpl(
- listOf("password")
- )
-
@Test
fun `custom span properties are redacted if they are sensitive`() {
testRule.runTest(
- setupAction = {
- overriddenConfigService.sensitiveKeysBehavior = sensitiveKeysBehavior
- },
+ instrumentedConfig = instrumentedConfig,
testCaseAction = {
recordSession {
embrace.startSpan("test span")?.apply {
@@ -49,9 +49,7 @@ internal class SensitiveKeysRedactionFeatureTest {
@Test
fun `custom span events are redacted if they are sensitive`() {
testRule.runTest(
- setupAction = {
- overriddenConfigService.sensitiveKeysBehavior = sensitiveKeysBehavior
- },
+ instrumentedConfig = instrumentedConfig,
testCaseAction = {
recordSession {
embrace.startSpan("test span")?.apply {
@@ -78,4 +76,4 @@ internal class SensitiveKeysRedactionFeatureTest {
}
)
}
-}
\ No newline at end of file
+}
diff --git a/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testcases/features/SessionPropertiesTest.kt b/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testcases/features/SessionPropertiesTest.kt
index 3639692c08..ad3587b6e4 100644
--- a/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testcases/features/SessionPropertiesTest.kt
+++ b/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testcases/features/SessionPropertiesTest.kt
@@ -3,6 +3,10 @@ package io.embrace.android.embracesdk.testcases.features
import androidx.test.ext.junit.runners.AndroidJUnit4
import io.embrace.android.embracesdk.Embrace
import io.embrace.android.embracesdk.assertions.findSessionSpan
+import io.embrace.android.embracesdk.fakes.config.FakeEnabledFeatureConfig
+import io.embrace.android.embracesdk.fakes.config.FakeInstrumentedConfig
+import io.embrace.android.embracesdk.fakes.createBackgroundActivityBehavior
+import io.embrace.android.embracesdk.internal.config.remote.BackgroundActivityRemoteConfig
import io.embrace.android.embracesdk.internal.payload.ApplicationState
import io.embrace.android.embracesdk.internal.payload.Span
import io.embrace.android.embracesdk.internal.spans.getSessionProperty
@@ -25,6 +29,7 @@ internal class SessionPropertiesTest {
@Test
fun `session properties additions and removal works at all stages app state transition`() {
testRule.runTest(
+ instrumentedConfig = FakeInstrumentedConfig(enabledFeatures = FakeEnabledFeatureConfig(bgActivityCapture = true)),
setupAction = {
setupPermanentProperties()
},
@@ -67,7 +72,6 @@ internal class SessionPropertiesTest {
fun `session properties work with background activity disabled`() {
testRule.runTest(
setupAction = {
- overriddenConfigService.backgroundActivityCaptureEnabled = false
setupPermanentProperties()
},
testCaseAction = {
@@ -114,7 +118,6 @@ internal class SessionPropertiesTest {
fun `session properties are persisted in cached payloads when bg activities are disabled`() {
testRule.runTest(
setupAction = {
- overriddenConfigService.backgroundActivityCaptureEnabled = false
setupPermanentProperties()
},
testCaseAction = {
diff --git a/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testcases/features/ThermalStateTest.kt b/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testcases/features/ThermalStateTest.kt
index 0a91c43f2d..24ea35d84b 100644
--- a/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testcases/features/ThermalStateTest.kt
+++ b/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testcases/features/ThermalStateTest.kt
@@ -5,7 +5,6 @@ import android.os.PowerManager
import androidx.test.ext.junit.runners.AndroidJUnit4
import io.embrace.android.embracesdk.assertions.findSpanSnapshotOfType
import io.embrace.android.embracesdk.assertions.findSpansOfType
-import io.embrace.android.embracesdk.fakes.behavior.FakeAutoDataCaptureBehavior
import io.embrace.android.embracesdk.internal.arch.schema.EmbType
import io.embrace.android.embracesdk.internal.clock.nanosToMillis
import io.embrace.android.embracesdk.internal.spans.findAttributeValue
@@ -26,16 +25,11 @@ internal class ThermalStateFeatureTest {
@JvmField
val testRule: IntegrationTestRule = IntegrationTestRule()
- private val autoDataCaptureBehavior = FakeAutoDataCaptureBehavior(thermalStatusCaptureEnabled = true)
-
@Test
fun `single thermal state change generates a snapshot`() {
var startTimeMs = 0L
testRule.runTest(
- setupAction = {
- overriddenConfigService.autoDataCaptureBehavior = autoDataCaptureBehavior
- },
testCaseAction = {
recordSession {
startTimeMs = clock.now()
@@ -64,9 +58,6 @@ internal class ThermalStateFeatureTest {
var startTimeMs = 0L
testRule.runTest(
- setupAction = {
- overriddenConfigService.autoDataCaptureBehavior = autoDataCaptureBehavior
- },
testCaseAction = {
recordSession {
startTimeMs = clock.now()
diff --git a/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testcases/features/V1DeliveryFeatureTest.kt b/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testcases/features/V1DeliveryFeatureTest.kt
index 42225d2031..90465f3265 100644
--- a/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testcases/features/V1DeliveryFeatureTest.kt
+++ b/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testcases/features/V1DeliveryFeatureTest.kt
@@ -7,7 +7,9 @@ import android.content.Context
import android.os.Build
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
-import io.embrace.android.embracesdk.fakes.behavior.FakeAutoDataCaptureBehavior
+import io.embrace.android.embracesdk.internal.config.remote.BackgroundActivityRemoteConfig
+import io.embrace.android.embracesdk.internal.config.remote.KillSwitchRemoteConfig
+import io.embrace.android.embracesdk.internal.config.remote.RemoteConfig
import io.embrace.android.embracesdk.internal.payload.ApplicationState
import io.embrace.android.embracesdk.testframework.IntegrationTestRule
import io.embrace.android.embracesdk.testframework.assertions.assertMatches
@@ -30,15 +32,17 @@ internal class V1DeliveryFeatureTest {
@JvmField
val testRule: IntegrationTestRule = IntegrationTestRule()
- private val behavior = FakeAutoDataCaptureBehavior(v2StorageEnabled = false)
+ private val remoteConfig = RemoteConfig(
+ killSwitchConfig = KillSwitchRemoteConfig(v2StoragePct = 0f),
+ backgroundActivityConfig = BackgroundActivityRemoteConfig(100f)
+ )
- @Suppress("DEPRECATION")
@Test
fun `v1 session delivery`() {
testRule.runTest(
+ persistedRemoteConfig = remoteConfig,
setupAction = {
useMockWebServer = false
- overriddenConfigService.autoDataCaptureBehavior = behavior
},
testCaseAction = {
recordSession {
@@ -52,13 +56,12 @@ internal class V1DeliveryFeatureTest {
)
}
- @Suppress("DEPRECATION")
@Test
fun `v1 background activity delivery`() {
testRule.runTest(
+ persistedRemoteConfig = remoteConfig,
setupAction = {
useMockWebServer = false
- overriddenConfigService.autoDataCaptureBehavior = behavior
},
testCaseAction = {
embrace.setUserIdentifier("foo")
@@ -74,9 +77,9 @@ internal class V1DeliveryFeatureTest {
@Test
fun `v1 crash delivery`() {
testRule.runTest(
+ persistedRemoteConfig = remoteConfig,
setupAction = {
useMockWebServer = false
- overriddenConfigService.autoDataCaptureBehavior = behavior
},
testCaseAction = {
recordSession {
@@ -93,9 +96,9 @@ internal class V1DeliveryFeatureTest {
@Test
fun `v1 log delivery`() {
testRule.runTest(
+ persistedRemoteConfig = remoteConfig,
setupAction = {
useMockWebServer = false
- overriddenConfigService.autoDataCaptureBehavior = behavior
setupFakeAeiData()
},
testCaseAction = {
diff --git a/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testcases/features/WebviewFeatureTest.kt b/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testcases/features/WebviewFeatureTest.kt
index 896696fd73..1a28dbf3d4 100644
--- a/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testcases/features/WebviewFeatureTest.kt
+++ b/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testcases/features/WebviewFeatureTest.kt
@@ -5,7 +5,6 @@ import com.squareup.moshi.Types
import io.embrace.android.embracesdk.ResourceReader
import io.embrace.android.embracesdk.assertions.findEventsOfType
import io.embrace.android.embracesdk.assertions.findSessionSpan
-import io.embrace.android.embracesdk.fakes.behavior.FakeWebViewVitalsBehavior
import io.embrace.android.embracesdk.internal.arch.schema.EmbType
import io.embrace.android.embracesdk.internal.payload.WebVital
import io.embrace.android.embracesdk.internal.payload.WebVitalType
@@ -33,9 +32,6 @@ internal class WebviewFeatureTest {
@Test
fun `webview info feature`() {
testRule.runTest(
- setupAction = {
- overriddenConfigService.webViewVitalsBehavior = FakeWebViewVitalsBehavior(50, true)
- },
testCaseAction = {
recordSession {
embrace.trackWebViewPerformance("myWebView", expectedCompleteData)
diff --git a/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testcases/session/BackgroundActivityDisabledTest.kt b/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testcases/session/BackgroundActivityDisabledTest.kt
index 208ed62c62..2d2e445343 100644
--- a/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testcases/session/BackgroundActivityDisabledTest.kt
+++ b/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testcases/session/BackgroundActivityDisabledTest.kt
@@ -56,9 +56,7 @@ internal class BackgroundActivityDisabledTest {
overriddenClock = clock,
overriddenInitModule = initModule,
overriddenWorkerThreadModule = workerThreadModule,
- ).apply {
- overriddenConfigService.backgroundActivityCaptureEnabled = false
- }
+ )
}
@Test
diff --git a/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testcases/session/BackgroundActivityTest.kt b/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testcases/session/BackgroundActivityTest.kt
index bcbd43259f..003f0d925f 100644
--- a/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testcases/session/BackgroundActivityTest.kt
+++ b/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testcases/session/BackgroundActivityTest.kt
@@ -5,6 +5,8 @@ import io.embrace.android.embracesdk.assertions.findSessionSpan
import io.embrace.android.embracesdk.assertions.getSessionId
import io.embrace.android.embracesdk.assertions.hasSpanSnapshotsOfType
import io.embrace.android.embracesdk.internal.arch.schema.EmbType
+import io.embrace.android.embracesdk.internal.config.remote.BackgroundActivityRemoteConfig
+import io.embrace.android.embracesdk.internal.config.remote.RemoteConfig
import io.embrace.android.embracesdk.internal.opentelemetry.embSessionNumber
import io.embrace.android.embracesdk.internal.payload.ApplicationState
import io.embrace.android.embracesdk.testframework.IntegrationTestRule
@@ -29,6 +31,7 @@ internal class BackgroundActivityTest {
@Test
fun `bg activity messages are recorded`() {
testRule.runTest(
+ persistedRemoteConfig = RemoteConfig(backgroundActivityConfig = BackgroundActivityRemoteConfig(100f)),
testCaseAction = {
recordSession()
clock.tick(30000)
diff --git a/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testcases/session/ManualSessionTest.kt b/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testcases/session/ManualSessionTest.kt
index fc7688de3f..2ab533129c 100644
--- a/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testcases/session/ManualSessionTest.kt
+++ b/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testcases/session/ManualSessionTest.kt
@@ -2,7 +2,8 @@ package io.embrace.android.embracesdk.testcases.session
import androidx.test.ext.junit.runners.AndroidJUnit4
import io.embrace.android.embracesdk.assertions.findSessionSpan
-import io.embrace.android.embracesdk.fakes.behavior.FakeSessionBehavior
+import io.embrace.android.embracesdk.internal.config.remote.RemoteConfig
+import io.embrace.android.embracesdk.internal.config.remote.SessionRemoteConfig
import io.embrace.android.embracesdk.internal.opentelemetry.embSessionNumber
import io.embrace.android.embracesdk.testframework.IntegrationTestRule
import io.embrace.android.embracesdk.testframework.assertions.assertMatches
@@ -47,10 +48,7 @@ internal class ManualSessionTest {
@Test
fun `calling endSession when session control enabled does not end sessions`() {
testRule.runTest(
- setupAction = {
- overriddenConfigService.sessionBehavior =
- FakeSessionBehavior(sessionControlEnabled = true)
- },
+ persistedRemoteConfig = RemoteConfig(sessionConfig = SessionRemoteConfig(isEnabled = true)),
testCaseAction = {
recordSession {
clock.tick(10000)
@@ -67,9 +65,7 @@ internal class ManualSessionTest {
@Test
fun `calling endSession when state session is below 5s has no effect`() {
testRule.runTest(
- setupAction = {
- overriddenConfigService.sessionBehavior = FakeSessionBehavior(sessionControlEnabled = true)
- },
+ persistedRemoteConfig = RemoteConfig(sessionConfig = SessionRemoteConfig(isEnabled = true)),
testCaseAction = {
recordSession {
clock.tick(1000) // not enough to trigger new session
diff --git a/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testcases/session/OtelSessionGatingTest.kt b/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testcases/session/OtelSessionGatingTest.kt
index ccbf055999..759977048b 100644
--- a/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testcases/session/OtelSessionGatingTest.kt
+++ b/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testcases/session/OtelSessionGatingTest.kt
@@ -5,8 +5,6 @@ import io.embrace.android.embracesdk.assertions.findSessionSpan
import io.embrace.android.embracesdk.assertions.hasEventOfType
import io.embrace.android.embracesdk.assertions.hasSpanOfType
import io.embrace.android.embracesdk.fakes.FakeAnrService
-import io.embrace.android.embracesdk.fakes.FakeConfigService
-import io.embrace.android.embracesdk.fakes.createSessionBehavior
import io.embrace.android.embracesdk.fakes.fakeCompletedAnrInterval
import io.embrace.android.embracesdk.fakes.fakeInProgressAnrInterval
import io.embrace.android.embracesdk.internal.EmbraceInternalApi
@@ -17,7 +15,6 @@ import io.embrace.android.embracesdk.internal.payload.Envelope
import io.embrace.android.embracesdk.internal.payload.SessionPayload
import io.embrace.android.embracesdk.testframework.IntegrationTestRule
import io.embrace.android.embracesdk.testframework.actions.EmbraceActionInterface
-import io.embrace.android.embracesdk.testframework.actions.EmbraceSetupInterface
import org.junit.Assert.assertEquals
import org.junit.Assert.assertNotNull
import org.junit.Rule
@@ -30,26 +27,14 @@ import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
internal class OtelSessionGatingTest {
- private var gatingConfig = SessionRemoteConfig(
- fullSessionEvents = setOf(),
- sessionComponents = setOf()
- )
-
@Rule
@JvmField
- val testRule: IntegrationTestRule = IntegrationTestRule {
- EmbraceSetupInterface(
- overriddenConfigService = FakeConfigService(
- sessionBehavior = createSessionBehavior(remoteCfg = { RemoteConfig(sessionConfig = gatingConfig) })
- )
- )
- }
+ val testRule: IntegrationTestRule = IntegrationTestRule()
@Test
fun `session sent in full without gating`() {
- gatingConfig = SessionRemoteConfig()
-
testRule.runTest(
+ persistedRemoteConfig = RemoteConfig(sessionConfig = SessionRemoteConfig()),
testCaseAction = {
simulateSession()
},
@@ -62,14 +47,16 @@ internal class OtelSessionGatingTest {
@Test
fun `session gated`() {
- gatingConfig = SessionRemoteConfig(
- sessionComponents = emptySet(),
- fullSessionEvents = setOf(
- "crashes",
- "errors"
- )
- )
testRule.runTest(
+ persistedRemoteConfig = RemoteConfig(
+ sessionConfig = SessionRemoteConfig(
+ sessionComponents = emptySet(),
+ fullSessionEvents = setOf(
+ "crashes",
+ "errors"
+ )
+ )
+ ),
testCaseAction = {
simulateSession()
},
diff --git a/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testcases/session/SessionSpamTest.kt b/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testcases/session/SessionSpamTest.kt
index 80c7aa2b15..e94a3a8731 100644
--- a/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testcases/session/SessionSpamTest.kt
+++ b/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testcases/session/SessionSpamTest.kt
@@ -2,6 +2,8 @@ package io.embrace.android.embracesdk.testcases.session
import androidx.test.ext.junit.runners.AndroidJUnit4
import io.embrace.android.embracesdk.assertions.getSessionId
+import io.embrace.android.embracesdk.fakes.config.FakeEnabledFeatureConfig
+import io.embrace.android.embracesdk.fakes.config.FakeInstrumentedConfig
import io.embrace.android.embracesdk.internal.payload.ApplicationState
import io.embrace.android.embracesdk.testframework.IntegrationTestRule
import org.junit.Assert.assertEquals
@@ -21,6 +23,7 @@ internal class SessionSpamTest {
@Test
fun `session messages are recorded`() {
testRule.runTest(
+ instrumentedConfig = FakeInstrumentedConfig(enabledFeatures = FakeEnabledFeatureConfig(bgActivityCapture = true)),
testCaseAction = {
repeat(SESSION_COUNT) {
recordSession {
diff --git a/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testcases/session/SessionSpanTest.kt b/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testcases/session/SessionSpanTest.kt
index 478f7642ee..785182b51d 100644
--- a/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testcases/session/SessionSpanTest.kt
+++ b/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testcases/session/SessionSpanTest.kt
@@ -1,6 +1,8 @@
package io.embrace.android.embracesdk.testcases.session
import androidx.test.ext.junit.runners.AndroidJUnit4
+import io.embrace.android.embracesdk.fakes.config.FakeEnabledFeatureConfig
+import io.embrace.android.embracesdk.fakes.config.FakeInstrumentedConfig
import io.embrace.android.embracesdk.internal.payload.getSessionSpan
import io.embrace.android.embracesdk.testframework.IntegrationTestRule
import org.junit.Assert.assertEquals
@@ -21,6 +23,7 @@ internal class SessionSpanTest {
val ids = mutableListOf()
testRule.runTest(
+ instrumentedConfig = FakeInstrumentedConfig(enabledFeatures = FakeEnabledFeatureConfig(bgActivityCapture = true)),
testCaseAction = {
recordSession {
ids.add(embrace.currentSessionId)
diff --git a/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testframework/IntegrationTestRule.kt b/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testframework/IntegrationTestRule.kt
index ae2b672b74..1640f41aab 100644
--- a/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testframework/IntegrationTestRule.kt
+++ b/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testframework/IntegrationTestRule.kt
@@ -1,14 +1,18 @@
package io.embrace.android.embracesdk.testframework
import android.content.Context
+import androidx.test.core.app.ApplicationProvider
import io.embrace.android.embracesdk.EmbraceHooks
import io.embrace.android.embracesdk.EmbraceImpl
import io.embrace.android.embracesdk.fakes.FakeClock
import io.embrace.android.embracesdk.fakes.FakeConfigService
import io.embrace.android.embracesdk.fakes.FakeDeliveryService
-import io.embrace.android.embracesdk.fakes.behavior.FakeSdkEndpointBehavior
+import io.embrace.android.embracesdk.fakes.TestPlatformSerializer
+import io.embrace.android.embracesdk.fakes.config.FakeBaseUrlConfig
+import io.embrace.android.embracesdk.fakes.config.FakeInstrumentedConfig
import io.embrace.android.embracesdk.fakes.injection.FakeCoreModule
import io.embrace.android.embracesdk.fakes.injection.FakeDeliveryModule
+import io.embrace.android.embracesdk.internal.config.remote.RemoteConfig
import io.embrace.android.embracesdk.internal.injection.CoreModule
import io.embrace.android.embracesdk.internal.injection.DeliveryModule
import io.embrace.android.embracesdk.internal.injection.EssentialServiceModule
@@ -23,6 +27,7 @@ import io.embrace.android.embracesdk.testframework.actions.EmbracePreSdkStartInt
import io.embrace.android.embracesdk.testframework.actions.EmbraceSetupInterface
import io.embrace.android.embracesdk.testframework.export.FilteredSpanExporter
import io.embrace.android.embracesdk.testframework.server.FakeApiServer
+import java.io.File
import okhttp3.Protocol
import okhttp3.mockwebserver.MockWebServer
import org.junit.Assert.assertEquals
@@ -93,6 +98,7 @@ internal class IntegrationTestRule(
private lateinit var otelAssertion: EmbraceOtelExportAssertionInterface
private lateinit var spanExporter: FilteredSpanExporter
private lateinit var embraceImpl: EmbraceImpl
+ private lateinit var baseUrl: String
lateinit var bootstrapper: ModuleInitBootstrapper
@@ -101,8 +107,11 @@ internal class IntegrationTestRule(
* assertions. This aims to enforce the better compartmentalisation & reuse of test code within
* the integration test suite.
*/
- inline fun runTest(
+ fun runTest(
startSdk: Boolean = true,
+ instrumentedConfig: FakeInstrumentedConfig = FakeInstrumentedConfig(),
+ persistedRemoteConfig: RemoteConfig = RemoteConfig(),
+ serverResponseConfig: RemoteConfig = persistedRemoteConfig,
expectSdkToStart: Boolean = startSdk,
setupAction: EmbraceSetupInterface.() -> Unit = {},
preSdkStartAction: EmbracePreSdkStartInterface.() -> Unit = {},
@@ -110,6 +119,26 @@ internal class IntegrationTestRule(
assertAction: EmbracePayloadAssertionInterface.() -> Unit = {},
otelExportAssertion: EmbraceOtelExportAssertionInterface.() -> Unit = {},
) {
+ setup = embraceSetupInterfaceSupplier()
+ var apiServer: FakeApiServer? = null
+
+ if (setup.useMockWebServer) {
+ apiServer = FakeApiServer(serverResponseConfig)
+ val server: MockWebServer = MockWebServer().apply {
+ protocols = listOf(Protocol.HTTP_2, Protocol.HTTP_1_1)
+ dispatcher = apiServer
+ start()
+ }
+ baseUrl = server.url("api").toString()
+ }
+
+ preSdkStart = EmbracePreSdkStartInterface(setup)
+ bootstrapper = setup.createBootstrapper(prepareConfig(instrumentedConfig))
+ action = EmbraceActionInterface(setup, bootstrapper)
+ payloadAssertion = EmbracePayloadAssertionInterface(bootstrapper, apiServer)
+ spanExporter = FilteredSpanExporter()
+ otelAssertion = EmbraceOtelExportAssertionInterface(spanExporter)
+
setupAction(setup)
with(setup) {
embraceImpl = EmbraceImpl(bootstrapper)
@@ -117,11 +146,16 @@ internal class IntegrationTestRule(
preSdkStartAction(preSdkStart)
embraceImpl.addSpanExporter(spanExporter)
+ // persist config here before the SDK starts up
+ persistConfig(persistedRemoteConfig)
+
if (startSdk) {
- embraceImpl.start(overriddenCoreModule.context, appFramework) {
- overriddenConfigService.apply { appFramework = it }
- }
- assertEquals(expectSdkToStart, bootstrapper.essentialServiceModule.processStateService.isInitialized())
+ embraceImpl.start(overriddenCoreModule.context)
+ assertEquals(
+ "SDK did not start in integration test.",
+ expectSdkToStart,
+ embraceImpl.isStarted
+ )
}
}
testCaseAction(action)
@@ -131,33 +165,34 @@ internal class IntegrationTestRule(
}
/**
- * Setup the Embrace SDK so it's ready for testing.
+ * Writes a config response to the expected location on disk so the SDK can read it.
*/
- override fun before() {
- setup = embraceSetupInterfaceSupplier.invoke()
- var apiServer: FakeApiServer? = null
+ private fun persistConfig(persistedRemoteConfig: RemoteConfig) {
+ val ctx = ApplicationProvider.getApplicationContext()
+ val storageDir = File(ctx.filesDir, "embrace_remote_config").apply {
+ mkdirs()
+ }
+ File(storageDir, "etag").writeText("persisted_etag")
+ val responseFile = File(storageDir, "most_recent_response")
- if (setup.useMockWebServer) {
- apiServer = FakeApiServer()
- val server: MockWebServer = MockWebServer().apply {
- protocols = listOf(Protocol.HTTP_2, Protocol.HTTP_1_1)
- dispatcher = apiServer
- start()
- }
- val baseUrl = server.url("api").toString()
+ responseFile.outputStream().buffered().use { stream ->
+ TestPlatformSerializer().toJson(persistedRemoteConfig, RemoteConfig::class.java, stream)
+ }
+ }
- setup.overriddenConfigService.sdkEndpointBehavior = FakeSdkEndpointBehavior(
- baseUrl,
- baseUrl
+ private fun prepareConfig(instrumentedConfig: FakeInstrumentedConfig) =
+ when {
+ setup.useMockWebServer -> instrumentedConfig.copy(
+ baseUrls = FakeBaseUrlConfig(configImpl = baseUrl, dataImpl = baseUrl)
)
+ else -> instrumentedConfig
}
- preSdkStart = EmbracePreSdkStartInterface(setup)
- bootstrapper = setup.createBootstrapper()
- action = EmbraceActionInterface(setup, bootstrapper)
- payloadAssertion = EmbracePayloadAssertionInterface(bootstrapper, apiServer)
- spanExporter = FilteredSpanExporter()
- otelAssertion = EmbraceOtelExportAssertionInterface(spanExporter)
+ /**
+ * Setup the Embrace SDK so it's ready for testing.
+ */
+ override fun before() {
+
}
/**
diff --git a/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testframework/actions/EmbraceActionInterface.kt b/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testframework/actions/EmbraceActionInterface.kt
index b5c768cdb8..58920fd1de 100644
--- a/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testframework/actions/EmbraceActionInterface.kt
+++ b/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testframework/actions/EmbraceActionInterface.kt
@@ -26,9 +26,6 @@ internal class EmbraceActionInterface(
val clock: FakeClock
get() = setup.overriddenClock
- val configService: FakeConfigService
- get() = setup.overriddenConfigService
-
/**
* Starts & ends a session for the purposes of testing. An action can be supplied as a lambda
* parameter: any code inside the lambda will be executed, so can be used to add breadcrumbs,
diff --git a/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testframework/actions/EmbracePayloadAssertionInterface.kt b/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testframework/actions/EmbracePayloadAssertionInterface.kt
index f9be427ff3..0c546b7cc1 100644
--- a/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testframework/actions/EmbracePayloadAssertionInterface.kt
+++ b/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testframework/actions/EmbracePayloadAssertionInterface.kt
@@ -1,12 +1,15 @@
package io.embrace.android.embracesdk.testframework.actions
+import android.content.Context
+import androidx.test.core.app.ApplicationProvider
import io.embrace.android.embracesdk.ResourceReader
import io.embrace.android.embracesdk.assertions.findSessionSpan
import io.embrace.android.embracesdk.assertions.getSessionId
import io.embrace.android.embracesdk.assertions.returnIfConditionMet
import io.embrace.android.embracesdk.fakes.FakeDeliveryService
import io.embrace.android.embracesdk.fakes.FakeNativeCrashService
-import io.embrace.android.embracesdk.fakes.FakeRequestExecutionService
+import io.embrace.android.embracesdk.internal.config.remote.RemoteConfig
+import io.embrace.android.embracesdk.internal.config.source.ConfigHttpResponse
import io.embrace.android.embracesdk.internal.injection.ModuleInitBootstrapper
import io.embrace.android.embracesdk.internal.opentelemetry.embCleanExit
import io.embrace.android.embracesdk.internal.opentelemetry.embState
@@ -17,6 +20,7 @@ import io.embrace.android.embracesdk.internal.payload.SessionPayload
import io.embrace.android.embracesdk.internal.spans.findAttributeValue
import io.embrace.android.embracesdk.testframework.assertions.JsonComparator
import io.embrace.android.embracesdk.testframework.server.FakeApiServer
+import java.io.File
import java.io.IOException
import java.util.Locale
import java.util.concurrent.TimeoutException
@@ -32,8 +36,14 @@ internal class EmbracePayloadAssertionInterface(
private val apiServer: FakeApiServer?,
) {
+ companion object {
+ private const val WAIT_TIME_MS = 10000
+ private const val CONFIG_OUTPUT_DIR = "embrace_remote_config"
+ private const val CONFIG_RESPONSE_FILE = "most_recent_response"
+ private const val CONFIG_ETAG_FILE = "etag"
+ }
+
private val deliveryService by lazy { bootstrapper.deliveryModule.deliveryService as FakeDeliveryService }
- private val requestExecutionService by lazy { bootstrapper.deliveryModule.requestExecutionService as FakeRequestExecutionService }
private val serializer by lazy { bootstrapper.initModule.jsonSerializer }
private val nativeCrashService by lazy {
bootstrapper.nativeFeatureModule.nativeCrashService as FakeNativeCrashService
@@ -55,17 +65,6 @@ internal class EmbracePayloadAssertionInterface(
return getLogEnvelopes(1).single()
}
- /**
- * Returns a list of logs that were completed by the SDK & sent to a mock web server.
- */
- internal fun getLogEnvelopesFromMockServer(
- expectedSize: Int,
- ): List> {
- return retrievePayload(expectedSize) {
- checkNotNull(apiServer).getLogEnvelopes()
- }
- }
-
private fun retrieveLogEnvelopes(
expectedSize: Int,
): List> {
@@ -136,7 +135,7 @@ internal class EmbracePayloadAssertionInterface(
internal fun getSessionEnvelopes(
expectedSize: Int,
state: ApplicationState = ApplicationState.FOREGROUND,
- waitTimeMs: Int = 1000,
+ waitTimeMs: Int = WAIT_TIME_MS,
): List> {
return retrieveSessionEnvelopes(expectedSize, state, waitTimeMs)
}
@@ -181,6 +180,63 @@ internal class EmbracePayloadAssertionInterface(
return ApplicationState.valueOf(value)
}
+
+ /*** Config ***/
+
+
+ internal fun assertConfigRequested(expectedRequests: Int) {
+ val supplier = {
+ checkNotNull(apiServer).getConfigRequests()
+ }
+ try {
+ retrievePayload(expectedRequests, supplier)
+ } catch (exc: TimeoutException) {
+ throw IllegalStateException(
+ "Expected $expectedRequests config requests, but got ${supplier().size}.",
+ exc
+ )
+ }
+ }
+
+ /**
+ * Asserts that config was persisted on disk and returns the persisted information.
+ */
+ internal fun readPersistedConfigResponse(): ConfigHttpResponse {
+ val ctx = ApplicationProvider.getApplicationContext()
+ val storageDir = File(ctx.filesDir, "embrace_remote_config")
+ if (!storageDir.exists()) {
+ throw IllegalStateException("Config storage directory does not exist.")
+ }
+ val responseFile = File(storageDir, "most_recent_response")
+ if (!responseFile.exists()) {
+ throw IllegalStateException("Config response file does not exist.")
+ }
+ val etagFile = File(storageDir, "etag")
+ if (!etagFile.exists()) {
+ throw IllegalStateException("Config etag file does not exist.")
+ }
+ val remoteConfig = readRemoteConfigFile(responseFile)
+ return ConfigHttpResponse(remoteConfig, readEtagFile(etagFile))
+ }
+
+ private fun readRemoteConfigFile(file: File): RemoteConfig {
+ try {
+ return file.inputStream().buffered().use {
+ serializer.fromJson(it, RemoteConfig::class.java)
+ }
+ } catch (exc: Throwable) {
+ throw IllegalStateException("Failed to read remote config file.", exc)
+ }
+ }
+
+ private fun readEtagFile(etagFile: File): String {
+ try {
+ return etagFile.readText()
+ } catch (exc: Throwable) {
+ throw IllegalStateException("Failed to read etag file for config.", exc)
+ }
+ }
+
/*** Native ***/
internal fun getSentNativeCrashes() = nativeCrashService.nativeCrashesSent.toList()
@@ -247,14 +303,14 @@ internal class EmbracePayloadAssertionInterface(
private inline fun retrievePayload(
expectedSize: Int?,
supplier: () -> List,
- ): List = retrievePayload(expectedSize, 1000, supplier)
+ ): List = retrievePayload(expectedSize, WAIT_TIME_MS, supplier)
/**
* Retrieves a payload that was stored in the delivery service.
*/
private inline fun retrievePayload(
expectedSize: Int?,
- waitTimeMs: Int = 1000,
+ waitTimeMs: Int = WAIT_TIME_MS,
supplier: () -> List,
): List {
return when (expectedSize) {
diff --git a/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testframework/actions/EmbracePreSdkStartInterface.kt b/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testframework/actions/EmbracePreSdkStartInterface.kt
index 2c02d206b7..a78a8f341e 100644
--- a/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testframework/actions/EmbracePreSdkStartInterface.kt
+++ b/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testframework/actions/EmbracePreSdkStartInterface.kt
@@ -1,7 +1,10 @@
package io.embrace.android.embracesdk.testframework.actions
+import android.content.Context
+import androidx.test.core.app.ApplicationProvider
import io.embrace.android.embracesdk.Embrace
import io.embrace.android.embracesdk.fakes.FakeClock
+import java.io.File
internal class EmbracePreSdkStartInterface(
private val setup: EmbraceSetupInterface,
@@ -10,4 +13,15 @@ internal class EmbracePreSdkStartInterface(
val clock: FakeClock
get() = setup.overriddenClock
-}
\ No newline at end of file
+
+ /**
+ * Asserts that no config has been persisted on disk yet.
+ */
+ internal fun assertNoConfigPersisted() {
+ val ctx = ApplicationProvider.getApplicationContext()
+ val storageDir = File(ctx.filesDir, "embrace_remote_config")
+ if (storageDir.exists()) {
+ throw IllegalStateException("Did not expect config storage directory to exist.")
+ }
+ }
+}
diff --git a/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testframework/actions/EmbraceSetupInterface.kt b/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testframework/actions/EmbraceSetupInterface.kt
index dc5b149aae..3283327aed 100644
--- a/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testframework/actions/EmbraceSetupInterface.kt
+++ b/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testframework/actions/EmbraceSetupInterface.kt
@@ -1,28 +1,24 @@
-@file:Suppress("DEPRECATION")
-
package io.embrace.android.embracesdk.testframework.actions
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.testing.TestLifecycleOwner
-import io.embrace.android.embracesdk.AppFramework
import io.embrace.android.embracesdk.fakes.FakeClock
-import io.embrace.android.embracesdk.fakes.FakeConfigService
import io.embrace.android.embracesdk.fakes.FakeDeliveryService
import io.embrace.android.embracesdk.fakes.FakeEmbLogger
import io.embrace.android.embracesdk.fakes.FakeNativeFeatureModule
import io.embrace.android.embracesdk.fakes.FakeNetworkConnectivityService
import io.embrace.android.embracesdk.fakes.FakeRequestExecutionService
-import io.embrace.android.embracesdk.fakes.behavior.FakeAutoDataCaptureBehavior
-import io.embrace.android.embracesdk.fakes.behavior.FakeNetworkSpanForwardingBehavior
+import io.embrace.android.embracesdk.fakes.config.FakeInstrumentedConfig
import io.embrace.android.embracesdk.fakes.injection.FakeAnrModule
import io.embrace.android.embracesdk.fakes.injection.FakeCoreModule
import io.embrace.android.embracesdk.fakes.injection.FakeInitModule
import io.embrace.android.embracesdk.fakes.injection.FakeNativeCoreModule
+import io.embrace.android.embracesdk.internal.comms.delivery.DeliveryService
+import io.embrace.android.embracesdk.internal.delivery.execution.RequestExecutionService
import io.embrace.android.embracesdk.internal.delivery.storage.PayloadStorageService
import io.embrace.android.embracesdk.internal.injection.AndroidServicesModule
import io.embrace.android.embracesdk.internal.injection.AnrModule
import io.embrace.android.embracesdk.internal.injection.ModuleInitBootstrapper
-import io.embrace.android.embracesdk.internal.injection.NativeCoreModule
import io.embrace.android.embracesdk.internal.injection.OpenTelemetryModule
import io.embrace.android.embracesdk.internal.injection.WorkerThreadModule
import io.embrace.android.embracesdk.internal.injection.createAndroidServicesModule
@@ -38,36 +34,32 @@ import io.embrace.android.embracesdk.testframework.IntegrationTestRule
internal class EmbraceSetupInterface @JvmOverloads constructor(
currentTimeMs: Long = IntegrationTestRule.DEFAULT_SDK_START_TIME_MS,
var useMockWebServer: Boolean = true,
- val appFramework: AppFramework = AppFramework.NATIVE,
val overriddenClock: FakeClock = FakeClock(currentTime = currentTimeMs),
val overriddenInitModule: FakeInitModule = FakeInitModule(clock = overriddenClock, logger = FakeEmbLogger()),
val overriddenOpenTelemetryModule: OpenTelemetryModule = overriddenInitModule.openTelemetryModule,
val overriddenCoreModule: FakeCoreModule = FakeCoreModule(),
- val overriddenConfigService: FakeConfigService = FakeConfigService(
- backgroundActivityCaptureEnabled = true,
- networkSpanForwardingBehavior = FakeNetworkSpanForwardingBehavior(true),
- autoDataCaptureBehavior = FakeAutoDataCaptureBehavior(thermalStatusCaptureEnabled = false)
- ),
val overriddenWorkerThreadModule: WorkerThreadModule = createWorkerThreadModule(),
val overriddenAndroidServicesModule: AndroidServicesModule = createAndroidServicesModule(
initModule = overriddenInitModule,
- coreModule = overriddenCoreModule,
- workerThreadModule = overriddenWorkerThreadModule
+ coreModule = overriddenCoreModule
),
val fakeAnrModule: AnrModule = FakeAnrModule(),
- val fakeNativeCoreModule: NativeCoreModule = FakeNativeCoreModule(),
val fakeNativeFeatureModule: FakeNativeFeatureModule = FakeNativeFeatureModule(),
- var cacheStorageServiceProvider: Provider = { null },
- var payloadStorageServiceProvider: Provider = { null },
+ var cacheStorageServiceProvider: Provider? = null,
+ var payloadStorageServiceProvider: Provider? = null,
val networkConnectivityService: FakeNetworkConnectivityService = FakeNetworkConnectivityService(),
val lifecycleOwner: TestLifecycleOwner = TestLifecycleOwner(initialState = Lifecycle.State.INITIALIZED),
) {
- fun createBootstrapper(): ModuleInitBootstrapper = ModuleInitBootstrapper(
- initModule = overriddenInitModule,
+ fun createBootstrapper(
+ instrumentedConfig: FakeInstrumentedConfig,
+ ): ModuleInitBootstrapper = ModuleInitBootstrapper(
+ initModule = overriddenInitModule.apply {
+ this.instrumentedConfig = instrumentedConfig
+ },
openTelemetryModule = overriddenInitModule.openTelemetryModule,
- coreModuleSupplier = { _ -> overriddenCoreModule },
+ coreModuleSupplier = { _, _ -> overriddenCoreModule },
workerThreadModuleSupplier = { overriddenWorkerThreadModule },
- androidServicesModuleSupplier = { _, _, _ -> overriddenAndroidServicesModule },
+ androidServicesModuleSupplier = { _, _ -> overriddenAndroidServicesModule },
essentialServiceModuleSupplier = { initModule, configModule, openTelemetryModule, coreModule, workerThreadModule, systemServiceModule, androidServicesModule, storageModule, _, _ ->
createEssentialServiceModule(
initModule,
@@ -81,7 +73,15 @@ internal class EmbraceSetupInterface @JvmOverloads constructor(
{ lifecycleOwner }
) { networkConnectivityService }
},
- deliveryModuleSupplier = { configModule, otelModule, initModule, workerThreadModule, coreModule, storageModule, essentialServiceModule, _, _, requestExecutionServiceProvider, deliveryServiceProvider ->
+ deliveryModuleSupplier = { configModule, otelModule, initModule, workerThreadModule, coreModule, storageModule, essentialServiceModule, androidServicesModule, _, _, _, _ ->
+ val requestExecutionServiceProvider: Provider? = when {
+ useMockWebServer -> null
+ else -> ::FakeRequestExecutionService
+ }
+ val deliveryServiceProvider: Provider? = when {
+ useMockWebServer -> null
+ else -> ::FakeDeliveryService
+ }
createDeliveryModule(
configModule,
otelModule,
@@ -90,23 +90,15 @@ internal class EmbraceSetupInterface @JvmOverloads constructor(
coreModule,
storageModule,
essentialServiceModule,
+ androidServicesModule,
payloadStorageServiceProvider = payloadStorageServiceProvider,
cacheStorageServiceProvider = cacheStorageServiceProvider,
- requestExecutionServiceProvider = {
- when {
- useMockWebServer -> requestExecutionServiceProvider()
- else -> FakeRequestExecutionService()
- }
- },
- deliveryServiceProvider = {
- when {
- useMockWebServer -> deliveryServiceProvider()
- else -> FakeDeliveryService()
- }
- })
+ requestExecutionServiceProvider = requestExecutionServiceProvider,
+ deliveryServiceProvider = deliveryServiceProvider
+ )
},
anrModuleSupplier = { _, _, _ -> fakeAnrModule },
- nativeCoreModuleSupplier = { fakeNativeCoreModule },
+ nativeCoreModuleSupplier = { FakeNativeCoreModule() },
nativeFeatureModuleSupplier = { _, _, _, _, _, _, _, _, _ -> fakeNativeFeatureModule }
)
}
diff --git a/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testframework/server/FakeApiServer.kt b/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testframework/server/FakeApiServer.kt
index d4967a9cbe..dc055162d9 100644
--- a/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testframework/server/FakeApiServer.kt
+++ b/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testframework/server/FakeApiServer.kt
@@ -2,7 +2,7 @@ package io.embrace.android.embracesdk.testframework.server
import io.embrace.android.embracesdk.fakes.TestPlatformSerializer
import io.embrace.android.embracesdk.internal.TypeUtils
-import io.embrace.android.embracesdk.internal.comms.api.Endpoint
+import io.embrace.android.embracesdk.internal.config.remote.RemoteConfig
import io.embrace.android.embracesdk.internal.payload.Envelope
import io.embrace.android.embracesdk.internal.payload.LogPayload
import io.embrace.android.embracesdk.internal.payload.SessionPayload
@@ -12,17 +12,27 @@ import java.util.zip.GZIPInputStream
import okhttp3.mockwebserver.Dispatcher
import okhttp3.mockwebserver.MockResponse
import okhttp3.mockwebserver.RecordedRequest
+import okio.Buffer
+import okio.GzipSink
+import okio.buffer
import org.junit.Assert.assertEquals
import org.junit.Assert.assertNotNull
/**
* Fake API server that is used to capture log/session requests made by the SDK in integration tests.
*/
-internal class FakeApiServer : Dispatcher() {
+internal class FakeApiServer(private val remoteConfig: RemoteConfig) : Dispatcher() {
+
+ private enum class Endpoint {
+ LOGS,
+ SESSIONS,
+ CONFIG
+ }
private val serializer by threadLocal { TestPlatformSerializer() }
private val sessionRequests = ConcurrentLinkedQueue>()
private val logRequests = ConcurrentLinkedQueue>()
+ private val configRequests = ConcurrentLinkedQueue()
/**
* Returns a list of session envelopes in the order in which the server received them.
@@ -34,20 +44,54 @@ internal class FakeApiServer : Dispatcher() {
*/
fun getLogEnvelopes(): List> = logRequests.toList()
- @Suppress("UNCHECKED_CAST")
+ /**
+ * Returns a list of config requests in the order in which the server received them.
+ * The returned value is the query parameter.
+ */
+ fun getConfigRequests(): List = configRequests.toList()
+
override fun dispatch(request: RecordedRequest): MockResponse {
- val endpoint = findRequestEndpoint(request)
+ return when (val endpoint = request.asEndpoint()) {
+ Endpoint.LOGS, Endpoint.SESSIONS -> handleEnvelopeRequest(request, endpoint)
+
+ // IMPORTANT NOTE: this response is not used until the SDK next starts!
+ Endpoint.CONFIG -> handleConfigRequest(request)
+ }
+ }
+
+ @Suppress("UNCHECKED_CAST")
+ private fun handleEnvelopeRequest(
+ request: RecordedRequest,
+ endpoint: Endpoint,
+ ): MockResponse {
val envelope = deserializeEnvelope(request, endpoint)
validateHeaders(request.headers.toMultimap().mapValues { it.value.joinToString() })
when (endpoint) {
Endpoint.SESSIONS -> sessionRequests.add(envelope as Envelope)
Endpoint.LOGS -> logRequests.add(envelope as Envelope)
- else -> error("Unsupported request type $endpoint")
+ else -> error("Unsupported endpoint $endpoint")
}
return MockResponse().setResponseCode(200)
}
+ private fun handleConfigRequest(request: RecordedRequest): MockResponse {
+ configRequests.add(request.requestUrl?.toUrl()?.query)
+
+ // serialize the config response
+ val configResponseBuffer = Buffer()
+ val gzipSink = GzipSink(configResponseBuffer).buffer()
+ serializer.toJson(
+ remoteConfig,
+ RemoteConfig::class.java,
+ gzipSink.outputStream()
+ )
+ return MockResponse()
+ .setBody(configResponseBuffer)
+ .addHeader("etag", "server_etag_value")
+ .setResponseCode(200)
+ }
+
private fun validateHeaders(headers: Map) {
with(headers) {
assertEquals("application/json", get("accept"))
@@ -58,11 +102,13 @@ internal class FakeApiServer : Dispatcher() {
}
}
- private fun findRequestEndpoint(request: RecordedRequest): Endpoint {
- return when (val path = request.path?.removePrefix("/api/v2/")) {
- Endpoint.LOGS.path -> Endpoint.LOGS
- Endpoint.SESSIONS.path -> Endpoint.SESSIONS
- else -> error("Unsupported path $path")
+ private fun RecordedRequest.asEndpoint(): Endpoint {
+ val path = requestUrl?.toUrl()?.path
+ return when (val endpoint = path?.removePrefix("/api/v2/")) {
+ "logs" -> Endpoint.LOGS
+ "spans" -> Endpoint.SESSIONS
+ "config" -> Endpoint.CONFIG
+ else -> error("Unsupported path $endpoint")
}
}
diff --git a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/EmbraceImpl.kt b/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/EmbraceImpl.kt
index 64b1252f71..b903312570 100644
--- a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/EmbraceImpl.kt
+++ b/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/EmbraceImpl.kt
@@ -118,34 +118,14 @@ internal class EmbraceImpl @JvmOverloads constructor(
}
@Suppress("DEPRECATION")
- override fun start(context: Context) = start(context, io.embrace.android.embracesdk.AppFramework.NATIVE) { null }
+ override fun start(context: Context) = start(context, io.embrace.android.embracesdk.AppFramework.NATIVE)
@Suppress("DEPRECATION")
@Deprecated("Use {@link #start(Context)} instead.", ReplaceWith("start(context)"))
- override fun start(context: Context, appFramework: io.embrace.android.embracesdk.AppFramework) =
- start(context, appFramework) { null }
-
- /**
- * Starts instrumentation of the Android application using the Embrace SDK. This should be
- * called during creation of the application, as early as possible.
- *
- * See [Embrace Docs](https://embrace.io/docs/android/) for
- * integration instructions. For compatibility with other networking SDKs such as Akamai,
- * the Embrace SDK must be initialized after any other SDK.
- *
- * @param context an instance of context
- * @param appFramework the AppFramework of the application
- * @param configServiceProvider provider for the config service
- */
- @Suppress("DEPRECATION")
- fun start(
- context: Context,
- appFramework: io.embrace.android.embracesdk.AppFramework,
- configServiceProvider: (framework: AppFramework) -> ConfigService? = { null },
- ) {
+ override fun start(context: Context, appFramework: io.embrace.android.embracesdk.AppFramework) {
try {
startSynchronous("sdk-start")
- startImpl(context, appFramework, configServiceProvider)
+ startImpl(context, appFramework)
endSynchronous()
} catch (t: Throwable) {
runCatching {
@@ -157,8 +137,7 @@ internal class EmbraceImpl @JvmOverloads constructor(
@Suppress("DEPRECATION", "CyclomaticComplexMethod", "ComplexMethod")
private fun startImpl(
context: Context,
- framework: io.embrace.android.embracesdk.AppFramework,
- configServiceProvider: (framework: AppFramework) -> ConfigService?,
+ framework: io.embrace.android.embracesdk.AppFramework
) {
if (application != null) {
return
@@ -167,17 +146,18 @@ internal class EmbraceImpl @JvmOverloads constructor(
val startTimeMs = sdkClock.now()
val appFramework = fromFramework(framework)
- bootstrapper.init(context, appFramework, startTimeMs, configServiceProvider)
+ if (!bootstrapper.init(context, appFramework, startTimeMs)) {
+ if (bootstrapper.configModule.configService.sdkModeBehavior.isSdkDisabled()) {
+ stop()
+ }
+ return
+ }
startSynchronous("post-services-setup")
val coreModule = bootstrapper.coreModule
application = coreModule.application
val configModule = bootstrapper.configModule
- if (configModule.configService.isSdkDisabled()) {
- stop()
- return
- }
if (configModule.configService.autoDataCaptureBehavior.isComposeClickCaptureEnabled()) {
registerComposeActivityListener(coreModule.application)
diff --git a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/injection/ModuleInitBootstrapper.kt b/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/injection/ModuleInitBootstrapper.kt
index 7ec29a8f96..84ddae9a2c 100644
--- a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/injection/ModuleInitBootstrapper.kt
+++ b/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/injection/ModuleInitBootstrapper.kt
@@ -1,14 +1,8 @@
package io.embrace.android.embracesdk.internal.injection
import android.content.Context
-import io.embrace.android.embracesdk.core.BuildConfig
-import io.embrace.android.embracesdk.internal.EmbraceInternalApi
import io.embrace.android.embracesdk.internal.Systrace
import io.embrace.android.embracesdk.internal.capture.envelope.session.OtelPayloadMapperImpl
-import io.embrace.android.embracesdk.internal.comms.delivery.EmbraceDeliveryService
-import io.embrace.android.embracesdk.internal.config.ConfigService
-import io.embrace.android.embracesdk.internal.delivery.execution.HttpUrlConnectionRequestExecutionService
-import io.embrace.android.embracesdk.internal.delivery.execution.OkHttpRequestExecutionService
import io.embrace.android.embracesdk.internal.logging.EmbLogger
import io.embrace.android.embracesdk.internal.logging.EmbLoggerImpl
import io.embrace.android.embracesdk.internal.logging.InternalErrorType
@@ -117,7 +111,6 @@ internal class ModuleInitBootstrapper(
context: Context,
appFramework: AppFramework,
sdkStartTimeMs: Long,
- configServiceProvider: (framework: AppFramework) -> ConfigService? = { null },
versionChecker: VersionChecker = BuildVersionChecker,
): Boolean {
try {
@@ -128,9 +121,8 @@ internal class ModuleInitBootstrapper(
synchronized(initialized) {
val result = if (!isInitialized()) {
- coreModule = init(CoreModule::class) { coreModuleSupplier(context) }
+ coreModule = init(CoreModule::class) { coreModuleSupplier(context, initModule) }
- val serviceRegistry = coreModule.serviceRegistry
workerThreadModule = init(WorkerThreadModule::class) {
workerThreadModuleSupplier()
}
@@ -141,33 +133,45 @@ internal class ModuleInitBootstrapper(
}
}
- systemServiceModule = init(SystemServiceModule::class) {
- systemServiceModuleSupplier(coreModule, versionChecker)
- }
-
androidServicesModule = init(AndroidServicesModule::class) {
- androidServicesModuleSupplier(initModule, coreModule, workerThreadModule)
+ androidServicesModuleSupplier(initModule, coreModule)
}
configModule = init(ConfigModule::class) {
configModuleSupplier(
initModule,
+ coreModule,
openTelemetryModule,
workerThreadModule,
androidServicesModule,
- appFramework,
- configServiceProvider,
- ) {
- if (isSdkDisabled()) {
- EmbraceInternalApi.getInstance().internalInterface.stopSdk()
+ appFramework
+ )
+ }
+
+ Systrace.traceSynchronous("sdk-disable-check") {
+ // kick off config HTTP request first so the SDK can't get in a permanently disabled state
+ Systrace.traceSynchronous("load-config-response") {
+ configModule.combinedRemoteConfigSource?.scheduleConfigRequests()
+ }
+
+ Systrace.traceSynchronous("behavior-check") {
+ if (configModule.configService.sdkModeBehavior.isSdkDisabled()) {
+ return false
}
}
}
+
+ val serviceRegistry = coreModule.serviceRegistry
postInit(ConfigModule::class) {
serviceRegistry.registerService(lazy { configModule.configService })
+ serviceRegistry.registerService(lazy { configModule.remoteConfigSource })
openTelemetryModule.setupSensitiveKeysBehavior(configModule.configService.sensitiveKeysBehavior)
}
+ systemServiceModule = init(SystemServiceModule::class) {
+ systemServiceModuleSupplier(coreModule, versionChecker)
+ }
+
storageModule = init(StorageModule::class) {
storageModuleSupplier(initModule, coreModule, workerThreadModule)
}
@@ -187,10 +191,7 @@ internal class ModuleInitBootstrapper(
)
}
postInit(EssentialServiceModule::class) {
- // Allow config service to start making HTTP requests
with(essentialServiceModule) {
- configModule.configService.remoteConfigSource = apiService
-
serviceRegistry.registerServices(
lazy { essentialServiceModule.processStateService },
lazy { activityLifecycleTracker },
@@ -226,7 +227,6 @@ internal class ModuleInitBootstrapper(
dataSourceModule = init(DataSourceModule::class) {
dataSourceModuleSupplier(
initModule,
- configModule.configService,
workerThreadModule
)
}
@@ -285,49 +285,15 @@ internal class ModuleInitBootstrapper(
coreModule,
storageModule,
essentialServiceModule,
- { null },
- { null },
- {
- if (configModule.configService.isOnlyUsingOtelExporters()) {
- null
- } else {
- val appId = checkNotNull(configModule.configService.appId)
- val coreBaseUrl = configModule.configService.sdkEndpointBehavior.getData(appId)
- val lazyDeviceId = lazy(androidServicesModule.preferencesService::deviceIdentifier)
- if (configModule.configService.autoDataCaptureBehavior.shouldUseOkHttp()) {
- OkHttpRequestExecutionService(
- coreBaseUrl,
- lazyDeviceId,
- appId,
- BuildConfig.VERSION_NAME,
- logger,
- )
- } else {
- HttpUrlConnectionRequestExecutionService(
- coreBaseUrl,
- lazyDeviceId,
- appId,
- BuildConfig.VERSION_NAME,
- logger,
- )
- }
- }
- },
- {
- val apiService = essentialServiceModule.apiService
- if (configModule.configService.isOnlyUsingOtelExporters() || apiService == null) {
- null
- } else {
- EmbraceDeliveryService(
- storageModule.deliveryCacheManager,
- apiService,
- initModule.jsonSerializer
- )
- }
- }
+ androidServicesModule,
+ null,
+ null,
+ null,
+ null
)
- }.apply {
- payloadCachingService?.run {
+ }
+ postInit(DeliveryModule::class) {
+ deliveryModule.payloadCachingService?.run {
openTelemetryModule.spanRepository.setSpanUpdateNotifier {
reportBackgroundActivityStateChange()
}
@@ -493,7 +459,6 @@ internal class ModuleInitBootstrapper(
if (isInitialized()) {
coreModule.serviceRegistry.close()
workerThreadModule.close()
- essentialServiceModule.processStateService.close()
initialized.set(false)
}
}
diff --git a/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/fakes/FakeModuleInitBootstrapper.kt b/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/fakes/FakeModuleInitBootstrapper.kt
index 9df07d2ca5..c3dcc2105c 100644
--- a/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/fakes/FakeModuleInitBootstrapper.kt
+++ b/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/fakes/FakeModuleInitBootstrapper.kt
@@ -37,16 +37,16 @@ internal fun fakeModuleInitBootstrapper(
fakeEmbLogger: FakeEmbLogger = FakeEmbLogger(),
fakeInitModule: FakeInitModule = FakeInitModule(logger = fakeEmbLogger),
fakeOpenTelemetryModule: FakeOpenTelemetryModule = FakeOpenTelemetryModule(),
- coreModuleSupplier: CoreModuleSupplier = { _ -> FakeCoreModule() },
+ coreModuleSupplier: CoreModuleSupplier = { _, _ -> FakeCoreModule() },
systemServiceModuleSupplier: SystemServiceModuleSupplier = { _, _ -> FakeSystemServiceModule() },
- androidServicesModuleSupplier: AndroidServicesModuleSupplier = { _, _, _ -> FakeAndroidServicesModule() },
+ androidServicesModuleSupplier: AndroidServicesModuleSupplier = { _, _ -> FakeAndroidServicesModule() },
workerThreadModuleSupplier: WorkerThreadModuleSupplier = { FakeWorkerThreadModule() },
storageModuleSupplier: StorageModuleSupplier = { _, _, _ -> FakeStorageModule() },
essentialServiceModuleSupplier: EssentialServiceModuleSupplier = { _, _, _, _, _, _, _, _, _, _ -> FakeEssentialServiceModule() },
- configModuleSupplier: ConfigModuleSupplier = { _, _, _, _, _, _, _ -> FakeConfigModule() },
- dataSourceModuleSupplier: DataSourceModuleSupplier = { _, _, _ -> FakeDataSourceModule() },
+ configModuleSupplier: ConfigModuleSupplier = { _, _, _, _, _, _ -> FakeConfigModule() },
+ dataSourceModuleSupplier: DataSourceModuleSupplier = { _, _ -> FakeDataSourceModule() },
dataCaptureServiceModuleSupplier: DataCaptureServiceModuleSupplier = { _, _, _, _, _, _ -> FakeDataCaptureServiceModule() },
- deliveryModuleSupplier: DeliveryModuleSupplier = { _, _, _, _, _, _, _, _, _, _, _ -> FakeDeliveryModule() },
+ deliveryModuleSupplier: DeliveryModuleSupplier = { _, _, _, _, _, _, _, _, _, _, _, _ -> FakeDeliveryModule() },
anrModuleSupplier: AnrModuleSupplier = { _, _, _ -> FakeAnrModule() },
logModuleSupplier: LogModuleSupplier = { _, _, _, _, _, _, _, _ -> FakeLogModule() },
nativeCoreModuleSupplier: NativeCoreModuleSupplier = { _ -> FakeNativeCoreModule() },
diff --git a/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/injection/EssentialServiceModuleImplTest.kt b/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/injection/EssentialServiceModuleImplTest.kt
index 54181c55e2..8563ce8ebe 100644
--- a/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/injection/EssentialServiceModuleImplTest.kt
+++ b/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/injection/EssentialServiceModuleImplTest.kt
@@ -40,7 +40,6 @@ internal class EssentialServiceModuleImplTest {
)
assertNotNull(module.processStateService)
- assertNotNull(module.urlBuilder)
assertNotNull(module.apiClient)
assertNotNull(module.apiService)
assertNotNull(module.activityLifecycleTracker)
diff --git a/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/injection/ModuleInitBootstrapperTest.kt b/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/injection/ModuleInitBootstrapperTest.kt
index 0523b3c308..77801b3b23 100644
--- a/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/injection/ModuleInitBootstrapperTest.kt
+++ b/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/injection/ModuleInitBootstrapperTest.kt
@@ -32,8 +32,8 @@ internal class ModuleInitBootstrapperTest {
logger = EmbLoggerImpl()
coreModule = FakeCoreModule()
moduleInitBootstrapper = ModuleInitBootstrapper(
- configModuleSupplier = { _, _, _, _, _, _, _ -> FakeConfigModule(FakeConfigService()) },
- coreModuleSupplier = { _ -> coreModule },
+ configModuleSupplier = { _, _, _, _, _, _ -> FakeConfigModule(FakeConfigService()) },
+ coreModuleSupplier = { _, _ -> coreModule },
nativeFeatureModuleSupplier = { _, _, _, _, _, _, _, _, _ -> FakeNativeFeatureModule() },
logger = logger
)
diff --git a/embrace-test-fakes/build.gradle.kts b/embrace-test-fakes/build.gradle.kts
index 592b9536f3..a154a20657 100644
--- a/embrace-test-fakes/build.gradle.kts
+++ b/embrace-test-fakes/build.gradle.kts
@@ -22,6 +22,7 @@ dependencies {
compileOnly(libs.opentelemetry.semconv.incubating)
implementation(libs.junit)
+ implementation(libs.okhttp)
implementation(libs.robolectric)
implementation(libs.lifecycle.runtime)
}
diff --git a/embrace-test-fakes/src/main/kotlin/io/embrace/android/embracesdk/fakes/Behavior.kt b/embrace-test-fakes/src/main/kotlin/io/embrace/android/embracesdk/fakes/Behavior.kt
index df6668df75..3f5eb3495b 100644
--- a/embrace-test-fakes/src/main/kotlin/io/embrace/android/embracesdk/fakes/Behavior.kt
+++ b/embrace-test-fakes/src/main/kotlin/io/embrace/android/embracesdk/fakes/Behavior.kt
@@ -17,8 +17,6 @@ import io.embrace.android.embracesdk.internal.config.behavior.NetworkBehavior
import io.embrace.android.embracesdk.internal.config.behavior.NetworkBehaviorImpl
import io.embrace.android.embracesdk.internal.config.behavior.NetworkSpanForwardingBehavior
import io.embrace.android.embracesdk.internal.config.behavior.NetworkSpanForwardingBehaviorImpl
-import io.embrace.android.embracesdk.internal.config.behavior.SdkEndpointBehavior
-import io.embrace.android.embracesdk.internal.config.behavior.SdkEndpointBehaviorImpl
import io.embrace.android.embracesdk.internal.config.behavior.SdkModeBehavior
import io.embrace.android.embracesdk.internal.config.behavior.SdkModeBehaviorImpl
import io.embrace.android.embracesdk.internal.config.behavior.SensitiveKeysBehaviorImpl
@@ -26,12 +24,8 @@ import io.embrace.android.embracesdk.internal.config.behavior.SessionBehavior
import io.embrace.android.embracesdk.internal.config.behavior.SessionBehaviorImpl
import io.embrace.android.embracesdk.internal.config.behavior.WebViewVitalsBehavior
import io.embrace.android.embracesdk.internal.config.behavior.WebViewVitalsBehaviorImpl
-import io.embrace.android.embracesdk.internal.config.remote.AnrRemoteConfig
-import io.embrace.android.embracesdk.internal.config.remote.BackgroundActivityRemoteConfig
-import io.embrace.android.embracesdk.internal.config.remote.LogRemoteConfig
-import io.embrace.android.embracesdk.internal.config.remote.NetworkSpanForwardingRemoteConfig
+import io.embrace.android.embracesdk.internal.config.instrumented.InstrumentedConfigImpl
import io.embrace.android.embracesdk.internal.config.remote.RemoteConfig
-import io.embrace.android.embracesdk.internal.utils.Provider
import io.embrace.android.embracesdk.internal.utils.Uuid
private val behaviorThresholdCheck = BehaviorThresholdCheck(Uuid::getEmbUuid)
@@ -41,98 +35,91 @@ private val behaviorThresholdCheck = BehaviorThresholdCheck(Uuid::getEmbUuid)
*/
fun createAnrBehavior(
thresholdCheck: BehaviorThresholdCheck = behaviorThresholdCheck,
- remoteCfg: Provider = { null },
-): AnrBehavior = AnrBehaviorImpl(thresholdCheck, remoteCfg)
+ remoteCfg: RemoteConfig? = null,
+): AnrBehavior = AnrBehaviorImpl(thresholdCheck, InstrumentedConfigImpl, remoteCfg)
/**
* A [SessionBehaviorImpl] that returns default values.
*/
fun createSessionBehavior(
- thresholdCheck: BehaviorThresholdCheck = behaviorThresholdCheck,
- remoteCfg: Provider = { null },
-): SessionBehavior = SessionBehaviorImpl(thresholdCheck, remoteCfg)
+ remoteCfg: RemoteConfig? = null,
+): SessionBehavior = SessionBehaviorImpl(InstrumentedConfigImpl, remoteCfg)
/**
* A [NetworkBehaviorImpl] that returns default values.
*/
fun createNetworkBehavior(
- thresholdCheck: BehaviorThresholdCheck = behaviorThresholdCheck,
- remoteCfg: Provider = { null },
+ remoteCfg: RemoteConfig? = null,
disabledUrlPatterns: List? = null,
-): NetworkBehavior = NetworkBehaviorImpl(thresholdCheck, remoteCfg, disabledUrlPatterns)
+): NetworkBehavior = NetworkBehaviorImpl(InstrumentedConfigImpl, remoteCfg, disabledUrlPatterns)
/**
* A [BackgroundActivityBehaviorImpl] that returns default values.
*/
fun createBackgroundActivityBehavior(
thresholdCheck: BehaviorThresholdCheck = behaviorThresholdCheck,
- remoteCfg: Provider = { null },
-): BackgroundActivityBehavior = BackgroundActivityBehaviorImpl(thresholdCheck, remoteCfg)
+ remoteCfg: RemoteConfig? = null,
+): BackgroundActivityBehavior = BackgroundActivityBehaviorImpl(thresholdCheck, InstrumentedConfigImpl, remoteCfg)
/**
* A [AutoDataCaptureBehaviorImpl] that returns default values.
*/
fun createAutoDataCaptureBehavior(
thresholdCheck: BehaviorThresholdCheck = behaviorThresholdCheck,
- remoteCfg: Provider = { null },
-): AutoDataCaptureBehavior = AutoDataCaptureBehaviorImpl(thresholdCheck, remoteCfg)
+ remoteCfg: RemoteConfig? = null,
+): AutoDataCaptureBehavior = AutoDataCaptureBehaviorImpl(thresholdCheck, InstrumentedConfigImpl, remoteCfg)
/**
* A [LogMessageBehaviorImpl] that returns default values.
*/
fun createLogMessageBehavior(
- thresholdCheck: BehaviorThresholdCheck = behaviorThresholdCheck,
- remoteCfg: Provider = { null },
-): LogMessageBehavior = LogMessageBehaviorImpl(thresholdCheck, remoteCfg)
+ remoteCfg: RemoteConfig? = null,
+): LogMessageBehavior = LogMessageBehaviorImpl(remoteCfg)
/**
* A [DataCaptureEventBehaviorImpl] that returns default values.
*/
fun createDataCaptureEventBehavior(
- thresholdCheck: BehaviorThresholdCheck = behaviorThresholdCheck,
- remoteCfg: Provider = { null },
-): DataCaptureEventBehavior = DataCaptureEventBehaviorImpl(thresholdCheck, remoteCfg)
+ remoteCfg: RemoteConfig? = null,
+): DataCaptureEventBehavior = DataCaptureEventBehaviorImpl(remoteCfg)
/**
* A [SdkModeBehaviorImpl] that returns default values.
*/
fun createSdkModeBehavior(
thresholdCheck: BehaviorThresholdCheck = behaviorThresholdCheck,
- remoteCfg: Provider = { null },
+ remoteCfg: RemoteConfig? = null,
): SdkModeBehavior = SdkModeBehaviorImpl(thresholdCheck, remoteCfg)
-/**
- * A [SdkModeBehaviorImpl] that returns default values.
- */
-fun createSdkEndpointBehavior(
- thresholdCheck: BehaviorThresholdCheck = behaviorThresholdCheck,
-): SdkEndpointBehavior = SdkEndpointBehaviorImpl(thresholdCheck)
-
/**
* A [AppExitInfoBehavior] that returns default values.
*/
fun createAppExitInfoBehavior(
thresholdCheck: BehaviorThresholdCheck = behaviorThresholdCheck,
- remoteCfg: Provider = { null },
-): AppExitInfoBehavior = AppExitInfoBehaviorImpl(thresholdCheck, remoteCfg)
+ remoteCfg: RemoteConfig? = null,
+): AppExitInfoBehavior = AppExitInfoBehaviorImpl(thresholdCheck, InstrumentedConfigImpl, remoteCfg)
/**
* A [NetworkSpanForwardingBehaviorImpl] that returns default values.
*/
fun createNetworkSpanForwardingBehavior(
thresholdCheck: BehaviorThresholdCheck = behaviorThresholdCheck,
- remoteConfig: Provider = { null },
-): NetworkSpanForwardingBehavior = NetworkSpanForwardingBehaviorImpl(thresholdCheck, remoteConfig)
+ remoteConfig: RemoteConfig? = null,
+): NetworkSpanForwardingBehavior = NetworkSpanForwardingBehaviorImpl(
+ thresholdCheck,
+ InstrumentedConfigImpl,
+ remoteConfig
+)
/**
* A [WebViewVitalsBehaviorImpl] that returns default values.
*/
fun createWebViewVitalsBehavior(
thresholdCheck: BehaviorThresholdCheck = behaviorThresholdCheck,
- remoteCfg: Provider = { null },
+ remoteCfg: RemoteConfig? = null,
): WebViewVitalsBehavior = WebViewVitalsBehaviorImpl(thresholdCheck, remoteCfg)
/**
* A [SensitiveKeysBehaviorImpl] that returns default values.
*/
-internal fun createSensitiveKeysBehavior() = SensitiveKeysBehaviorImpl()
+internal fun createSensitiveKeysBehavior() = SensitiveKeysBehaviorImpl(InstrumentedConfigImpl)
diff --git a/embrace-test-fakes/src/main/kotlin/io/embrace/android/embracesdk/fakes/FakeApiService.kt b/embrace-test-fakes/src/main/kotlin/io/embrace/android/embracesdk/fakes/FakeApiService.kt
index f6b8f60bc7..586eb34134 100644
--- a/embrace-test-fakes/src/main/kotlin/io/embrace/android/embracesdk/fakes/FakeApiService.kt
+++ b/embrace-test-fakes/src/main/kotlin/io/embrace/android/embracesdk/fakes/FakeApiService.kt
@@ -2,9 +2,7 @@ package io.embrace.android.embracesdk.fakes
import io.embrace.android.embracesdk.internal.comms.api.ApiResponse
import io.embrace.android.embracesdk.internal.comms.api.ApiService
-import io.embrace.android.embracesdk.internal.comms.api.CachedConfig
import io.embrace.android.embracesdk.internal.comms.delivery.NetworkStatus
-import io.embrace.android.embracesdk.internal.config.remote.RemoteConfig
import io.embrace.android.embracesdk.internal.injection.SerializationAction
import io.embrace.android.embracesdk.internal.payload.Envelope
import io.embrace.android.embracesdk.internal.payload.LogPayload
@@ -27,14 +25,6 @@ class FakeApiService : ApiService {
val sessionRequests: MutableList> = mutableListOf()
var futureGetCount: Int = 0
- override fun getConfig(): RemoteConfig? {
- TODO("Not yet implemented")
- }
-
- override fun getCachedConfig(): CachedConfig {
- TODO("Not yet implemented")
- }
-
override fun sendLogEnvelope(logEnvelope: Envelope) {
sentLogPayloads.add(logEnvelope.data)
}
diff --git a/embrace-test-fakes/src/main/kotlin/io/embrace/android/embracesdk/fakes/FakeApiUrlBuilder.kt b/embrace-test-fakes/src/main/kotlin/io/embrace/android/embracesdk/fakes/FakeApiUrlBuilder.kt
index 9de47a61ce..75e2607e7e 100644
--- a/embrace-test-fakes/src/main/kotlin/io/embrace/android/embracesdk/fakes/FakeApiUrlBuilder.kt
+++ b/embrace-test-fakes/src/main/kotlin/io/embrace/android/embracesdk/fakes/FakeApiUrlBuilder.kt
@@ -1,13 +1,12 @@
package io.embrace.android.embracesdk.fakes
import io.embrace.android.embracesdk.internal.comms.api.ApiUrlBuilder
+import io.embrace.android.embracesdk.internal.comms.api.Endpoint
-class FakeApiUrlBuilder : ApiUrlBuilder {
- override fun getConfigUrl(): String {
- return ""
- }
-
- override fun getEmbraceUrlWithSuffix(apiVersion: String, suffix: String): String {
- return ""
- }
+class FakeApiUrlBuilder(
+ override val appId: String = "",
+ override val deviceId: String = "",
+ override val baseDataUrl: String = "",
+) : ApiUrlBuilder {
+ override fun resolveUrl(endpoint: Endpoint): String = ""
}
diff --git a/embrace-test-fakes/src/main/kotlin/io/embrace/android/embracesdk/fakes/FakeConfigModule.kt b/embrace-test-fakes/src/main/kotlin/io/embrace/android/embracesdk/fakes/FakeConfigModule.kt
index 39bc131064..6b5a0795b3 100644
--- a/embrace-test-fakes/src/main/kotlin/io/embrace/android/embracesdk/fakes/FakeConfigModule.kt
+++ b/embrace-test-fakes/src/main/kotlin/io/embrace/android/embracesdk/fakes/FakeConfigModule.kt
@@ -1,8 +1,12 @@
package io.embrace.android.embracesdk.fakes
import io.embrace.android.embracesdk.fakes.behavior.FakeNetworkBehavior
+import io.embrace.android.embracesdk.internal.comms.api.ApiUrlBuilder
import io.embrace.android.embracesdk.internal.config.ConfigService
+import io.embrace.android.embracesdk.internal.config.source.CombinedRemoteConfigSource
+import io.embrace.android.embracesdk.internal.config.source.RemoteConfigSource
import io.embrace.android.embracesdk.internal.injection.ConfigModule
+import okhttp3.OkHttpClient
class FakeConfigModule(
override val configService: ConfigService = FakeConfigService(
@@ -10,4 +14,10 @@ class FakeConfigModule(
captureHttpUrlConnectionRequests = false
)
),
+ override val combinedRemoteConfigSource: CombinedRemoteConfigSource? = null,
+
+ override val remoteConfigSource: RemoteConfigSource = FakeRemoteConfigSource(),
+ override val remoteConfigStore: FakeRemoteConfigStore = FakeRemoteConfigStore(),
+ override val urlBuilder: ApiUrlBuilder = FakeApiUrlBuilder(),
+ override val okHttpClient: OkHttpClient = OkHttpClient(),
) : ConfigModule
diff --git a/embrace-test-fakes/src/main/kotlin/io/embrace/android/embracesdk/fakes/FakeConfigService.kt b/embrace-test-fakes/src/main/kotlin/io/embrace/android/embracesdk/fakes/FakeConfigService.kt
index 022dc87320..e39d48a8b9 100644
--- a/embrace-test-fakes/src/main/kotlin/io/embrace/android/embracesdk/fakes/FakeConfigService.kt
+++ b/embrace-test-fakes/src/main/kotlin/io/embrace/android/embracesdk/fakes/FakeConfigService.kt
@@ -1,7 +1,7 @@
package io.embrace.android.embracesdk.fakes
+import io.embrace.android.embracesdk.fakes.behavior.FakeBreadcrumbBehavior
import io.embrace.android.embracesdk.internal.config.ConfigService
-import io.embrace.android.embracesdk.internal.config.RemoteConfigSource
import io.embrace.android.embracesdk.internal.config.behavior.AnrBehavior
import io.embrace.android.embracesdk.internal.config.behavior.AppExitInfoBehavior
import io.embrace.android.embracesdk.internal.config.behavior.AutoDataCaptureBehavior
@@ -11,7 +11,6 @@ import io.embrace.android.embracesdk.internal.config.behavior.DataCaptureEventBe
import io.embrace.android.embracesdk.internal.config.behavior.LogMessageBehavior
import io.embrace.android.embracesdk.internal.config.behavior.NetworkBehavior
import io.embrace.android.embracesdk.internal.config.behavior.NetworkSpanForwardingBehavior
-import io.embrace.android.embracesdk.internal.config.behavior.SdkEndpointBehavior
import io.embrace.android.embracesdk.internal.config.behavior.SdkModeBehavior
import io.embrace.android.embracesdk.internal.config.behavior.SensitiveKeysBehavior
import io.embrace.android.embracesdk.internal.config.behavior.SessionBehavior
@@ -19,17 +18,14 @@ import io.embrace.android.embracesdk.internal.config.behavior.WebViewVitalsBehav
import io.embrace.android.embracesdk.internal.payload.AppFramework
/**
- * Fake [ConfigService] used for testing. Updates to registered listeners can be triggered by calling [updateListeners]. Note that the
+ * Fake [ConfigService] used for testing. Note that the
* current config values of this object will be propagated, and you can trigger this fake update even if you have not changed the underlying
* data. Beware of this difference in implementation compared to the real EmbraceConfigService
*/
class FakeConfigService(
override var appFramework: AppFramework = AppFramework.NATIVE,
override var appId: String = "abcde",
- var sdkDisabled: Boolean = false,
- var backgroundActivityCaptureEnabled: Boolean = false,
var onlyUsingOtelExporters: Boolean = false,
- private var hasValidRemoteConfig: Boolean = false,
override var backgroundActivityBehavior: BackgroundActivityBehavior = createBackgroundActivityBehavior(),
override var autoDataCaptureBehavior: AutoDataCaptureBehavior = createAutoDataCaptureBehavior(),
override var breadcrumbBehavior: BreadcrumbBehavior = FakeBreadcrumbBehavior(),
@@ -39,31 +35,10 @@ class FakeConfigService(
override var networkBehavior: NetworkBehavior = createNetworkBehavior(),
override var dataCaptureEventBehavior: DataCaptureEventBehavior = createDataCaptureEventBehavior(),
override var sdkModeBehavior: SdkModeBehavior = createSdkModeBehavior(),
- override var sdkEndpointBehavior: SdkEndpointBehavior = createSdkEndpointBehavior(),
override var webViewVitalsBehavior: WebViewVitalsBehavior = createWebViewVitalsBehavior(),
override var appExitInfoBehavior: AppExitInfoBehavior = createAppExitInfoBehavior(),
override var networkSpanForwardingBehavior: NetworkSpanForwardingBehavior = createNetworkSpanForwardingBehavior(),
override var sensitiveKeysBehavior: SensitiveKeysBehavior = createSensitiveKeysBehavior(),
) : ConfigService {
-
- override var remoteConfigSource: RemoteConfigSource? = null
-
- val listeners: MutableSet<() -> Unit> = mutableSetOf()
- override fun addListener(configListener: () -> Unit) {
- listeners.add(configListener)
- }
-
- override fun isSdkDisabled(): Boolean = sdkDisabled || sdkModeBehavior.isSdkDisabled()
-
- override fun isBackgroundActivityCaptureEnabled(): Boolean = backgroundActivityCaptureEnabled
-
- override fun hasValidRemoteConfig(): Boolean = hasValidRemoteConfig
- override fun isAppExitInfoCaptureEnabled(): Boolean = appExitInfoBehavior.isAeiCaptureEnabled()
override fun isOnlyUsingOtelExporters(): Boolean = onlyUsingOtelExporters
-
- fun updateListeners() {
- listeners.forEach {
- it()
- }
- }
}
diff --git a/embrace-test-fakes/src/main/kotlin/io/embrace/android/embracesdk/fakes/FakeDataSourceModule.kt b/embrace-test-fakes/src/main/kotlin/io/embrace/android/embracesdk/fakes/FakeDataSourceModule.kt
index 140c571db8..4984a8b3bf 100644
--- a/embrace-test-fakes/src/main/kotlin/io/embrace/android/embracesdk/fakes/FakeDataSourceModule.kt
+++ b/embrace-test-fakes/src/main/kotlin/io/embrace/android/embracesdk/fakes/FakeDataSourceModule.kt
@@ -7,7 +7,6 @@ import io.embrace.android.embracesdk.internal.injection.DataSourceModule
class FakeDataSourceModule : DataSourceModule {
override val dataCaptureOrchestrator: DataCaptureOrchestrator =
DataCaptureOrchestrator(
- FakeConfigService(),
fakeBackgroundWorker(),
FakeEmbLogger()
)
diff --git a/embrace-test-fakes/src/main/kotlin/io/embrace/android/embracesdk/fakes/FakePreferenceService.kt b/embrace-test-fakes/src/main/kotlin/io/embrace/android/embracesdk/fakes/FakePreferenceService.kt
index 4144d17a2c..27460d72c0 100644
--- a/embrace-test-fakes/src/main/kotlin/io/embrace/android/embracesdk/fakes/FakePreferenceService.kt
+++ b/embrace-test-fakes/src/main/kotlin/io/embrace/android/embracesdk/fakes/FakePreferenceService.kt
@@ -8,7 +8,6 @@ class FakePreferenceService(
override var osVersion: String? = null,
override var installDate: Long? = 0,
override var deviceIdentifier: String = "",
- override var sdkDisabled: Boolean = false,
override var userPayer: Boolean = false,
override var userIdentifier: String? = null,
override var userEmailAddress: String? = null,
@@ -16,13 +15,11 @@ class FakePreferenceService(
override var username: String? = null,
override var permanentSessionProperties: Map? = null,
override var lastConfigFetchDate: Long? = null,
- override var userMessageNeedsRetry: Boolean = false,
override var reactNativeVersionNumber: String? = null,
override var unityVersionNumber: String? = null,
override var unityBuildIdNumber: String? = null,
override var unitySdkVersionNumber: String? = null,
override var screenResolution: String? = null,
- override var backgroundActivityEnabled: Boolean = false,
override var dartSdkVersion: String? = null,
override var javaScriptBundleURL: String? = null,
override var javaScriptBundleId: String? = null,
diff --git a/embrace-test-fakes/src/main/kotlin/io/embrace/android/embracesdk/fakes/FakeRemoteConfigSource.kt b/embrace-test-fakes/src/main/kotlin/io/embrace/android/embracesdk/fakes/FakeRemoteConfigSource.kt
new file mode 100644
index 0000000000..ce31a67b61
--- /dev/null
+++ b/embrace-test-fakes/src/main/kotlin/io/embrace/android/embracesdk/fakes/FakeRemoteConfigSource.kt
@@ -0,0 +1,21 @@
+package io.embrace.android.embracesdk.fakes
+
+import io.embrace.android.embracesdk.internal.config.source.ConfigHttpResponse
+import io.embrace.android.embracesdk.internal.config.source.RemoteConfigSource
+
+class FakeRemoteConfigSource(
+ var cfg: ConfigHttpResponse? = null
+) : RemoteConfigSource {
+
+ var callCount: Int = 0
+ var etag: String? = null
+
+ override fun getConfig(): ConfigHttpResponse? {
+ callCount++
+ return cfg
+ }
+
+ override fun setInitialEtag(etag: String) {
+ this.etag = etag
+ }
+}
diff --git a/embrace-test-fakes/src/main/kotlin/io/embrace/android/embracesdk/fakes/FakeRemoteConfigStore.kt b/embrace-test-fakes/src/main/kotlin/io/embrace/android/embracesdk/fakes/FakeRemoteConfigStore.kt
new file mode 100644
index 0000000000..9974210a4b
--- /dev/null
+++ b/embrace-test-fakes/src/main/kotlin/io/embrace/android/embracesdk/fakes/FakeRemoteConfigStore.kt
@@ -0,0 +1,18 @@
+package io.embrace.android.embracesdk.fakes
+
+import io.embrace.android.embracesdk.internal.config.source.ConfigHttpResponse
+import io.embrace.android.embracesdk.internal.config.store.RemoteConfigStore
+
+class FakeRemoteConfigStore(
+ var impl: ConfigHttpResponse? = null,
+) : RemoteConfigStore {
+
+ var saveCount: Int = 0
+
+ override fun loadResponse(): ConfigHttpResponse? = impl
+
+ override fun saveResponse(response: ConfigHttpResponse) {
+ saveCount++
+ impl = response
+ }
+}
diff --git a/embrace-test-fakes/src/main/kotlin/io/embrace/android/embracesdk/fakes/behavior/FakeAnrBehavior.kt b/embrace-test-fakes/src/main/kotlin/io/embrace/android/embracesdk/fakes/behavior/FakeAnrBehavior.kt
index fbe4c24c65..7d8ba4bcc4 100644
--- a/embrace-test-fakes/src/main/kotlin/io/embrace/android/embracesdk/fakes/behavior/FakeAnrBehavior.kt
+++ b/embrace-test-fakes/src/main/kotlin/io/embrace/android/embracesdk/fakes/behavior/FakeAnrBehavior.kt
@@ -1,7 +1,9 @@
package io.embrace.android.embracesdk.fakes.behavior
import io.embrace.android.embracesdk.internal.config.behavior.AnrBehavior
+import io.embrace.android.embracesdk.internal.config.instrumented.schema.EnabledFeatureConfig
import io.embrace.android.embracesdk.internal.config.remote.AllowedNdkSampleMethod
+import io.embrace.android.embracesdk.internal.config.remote.AnrRemoteConfig
import io.embrace.android.embracesdk.internal.config.remote.Unwinder
class FakeAnrBehavior(
@@ -15,6 +17,11 @@ class FakeAnrBehavior(
var nativeThreadAnrSamplingAllowlistImpl: List = emptyList(),
) : AnrBehavior {
+ override val local: EnabledFeatureConfig
+ get() = throw UnsupportedOperationException()
+ override val remote: AnrRemoteConfig
+ get() = throw UnsupportedOperationException()
+
override fun isAnrCaptureEnabled(): Boolean = anrCaptureEnabled
override fun getSamplingIntervalMs(): Long = sampleIntervalMsImpl
override fun getMaxStacktracesPerInterval(): Int = 80
diff --git a/embrace-test-fakes/src/main/kotlin/io/embrace/android/embracesdk/fakes/behavior/FakeAppExitInfoBehavior.kt b/embrace-test-fakes/src/main/kotlin/io/embrace/android/embracesdk/fakes/behavior/FakeAppExitInfoBehavior.kt
index 596804196a..bddcb7349f 100644
--- a/embrace-test-fakes/src/main/kotlin/io/embrace/android/embracesdk/fakes/behavior/FakeAppExitInfoBehavior.kt
+++ b/embrace-test-fakes/src/main/kotlin/io/embrace/android/embracesdk/fakes/behavior/FakeAppExitInfoBehavior.kt
@@ -1,6 +1,8 @@
package io.embrace.android.embracesdk.fakes.behavior
import io.embrace.android.embracesdk.internal.config.behavior.AppExitInfoBehavior
+import io.embrace.android.embracesdk.internal.config.instrumented.schema.EnabledFeatureConfig
+import io.embrace.android.embracesdk.internal.config.remote.AppExitInfoConfig
class FakeAppExitInfoBehavior(
private val traceMaxLimit: Int = 20000000,
@@ -8,6 +10,11 @@ class FakeAppExitInfoBehavior(
private val appExitInfoMaxNum: Int = 0,
) : AppExitInfoBehavior {
+ override val local: EnabledFeatureConfig
+ get() = throw UnsupportedOperationException()
+ override val remote: AppExitInfoConfig
+ get() = throw UnsupportedOperationException()
+
override fun getTraceMaxLimit(): Int = traceMaxLimit
override fun isAeiCaptureEnabled(): Boolean = enabled
override fun appExitInfoMaxNum(): Int = appExitInfoMaxNum
diff --git a/embrace-test-fakes/src/main/kotlin/io/embrace/android/embracesdk/fakes/behavior/FakeAutoDataCaptureBehavior.kt b/embrace-test-fakes/src/main/kotlin/io/embrace/android/embracesdk/fakes/behavior/FakeAutoDataCaptureBehavior.kt
index be364a32f9..dce1e1830c 100644
--- a/embrace-test-fakes/src/main/kotlin/io/embrace/android/embracesdk/fakes/behavior/FakeAutoDataCaptureBehavior.kt
+++ b/embrace-test-fakes/src/main/kotlin/io/embrace/android/embracesdk/fakes/behavior/FakeAutoDataCaptureBehavior.kt
@@ -1,6 +1,8 @@
package io.embrace.android.embracesdk.fakes.behavior
import io.embrace.android.embracesdk.internal.config.behavior.AutoDataCaptureBehavior
+import io.embrace.android.embracesdk.internal.config.instrumented.schema.EnabledFeatureConfig
+import io.embrace.android.embracesdk.internal.config.remote.RemoteConfig
class FakeAutoDataCaptureBehavior(
private val memoryServiceEnabled: Boolean = true,
@@ -17,6 +19,11 @@ class FakeAutoDataCaptureBehavior(
private val useOkhttp: Boolean = true,
) : AutoDataCaptureBehavior {
+ override val local: EnabledFeatureConfig
+ get() = throw UnsupportedOperationException()
+ override val remote: RemoteConfig
+ get() = throw UnsupportedOperationException()
+
override fun isMemoryWarningCaptureEnabled(): Boolean = memoryServiceEnabled
override fun isThermalStatusCaptureEnabled(): Boolean = thermalStatusCaptureEnabled
override fun isPowerSaveModeCaptureEnabled(): Boolean = powerSaveModeServiceEnabled
diff --git a/embrace-test-fakes/src/main/kotlin/io/embrace/android/embracesdk/fakes/FakeBreadcrumbBehavior.kt b/embrace-test-fakes/src/main/kotlin/io/embrace/android/embracesdk/fakes/behavior/FakeBreadcrumbBehavior.kt
similarity index 76%
rename from embrace-test-fakes/src/main/kotlin/io/embrace/android/embracesdk/fakes/FakeBreadcrumbBehavior.kt
rename to embrace-test-fakes/src/main/kotlin/io/embrace/android/embracesdk/fakes/behavior/FakeBreadcrumbBehavior.kt
index fac0ab8466..482c29f541 100644
--- a/embrace-test-fakes/src/main/kotlin/io/embrace/android/embracesdk/fakes/FakeBreadcrumbBehavior.kt
+++ b/embrace-test-fakes/src/main/kotlin/io/embrace/android/embracesdk/fakes/behavior/FakeBreadcrumbBehavior.kt
@@ -1,6 +1,8 @@
-package io.embrace.android.embracesdk.fakes
+package io.embrace.android.embracesdk.fakes.behavior
import io.embrace.android.embracesdk.internal.config.behavior.BreadcrumbBehavior
+import io.embrace.android.embracesdk.internal.config.instrumented.schema.EnabledFeatureConfig
+import io.embrace.android.embracesdk.internal.config.remote.RemoteConfig
class FakeBreadcrumbBehavior(
var customBreadcrumbLimitImpl: Int = 100,
@@ -13,6 +15,12 @@ class FakeBreadcrumbBehavior(
var queryParamCaptureEnabled: Boolean = true,
var captureFcmPiiDataEnabled: Boolean = false,
) : BreadcrumbBehavior {
+
+ override val local: EnabledFeatureConfig
+ get() = throw UnsupportedOperationException()
+ override val remote: RemoteConfig
+ get() = throw UnsupportedOperationException()
+
override fun getCustomBreadcrumbLimit(): Int = customBreadcrumbLimitImpl
override fun getFragmentBreadcrumbLimit(): Int = fragmentBreadcrumbLimitImpl
override fun getTapBreadcrumbLimit(): Int = tapBreadcrumbLimitImpl
diff --git a/embrace-test-fakes/src/main/kotlin/io/embrace/android/embracesdk/fakes/behavior/FakeLogMessageBehavior.kt b/embrace-test-fakes/src/main/kotlin/io/embrace/android/embracesdk/fakes/behavior/FakeLogMessageBehavior.kt
index 9cfb2abb8c..dbd494a802 100644
--- a/embrace-test-fakes/src/main/kotlin/io/embrace/android/embracesdk/fakes/behavior/FakeLogMessageBehavior.kt
+++ b/embrace-test-fakes/src/main/kotlin/io/embrace/android/embracesdk/fakes/behavior/FakeLogMessageBehavior.kt
@@ -1,6 +1,7 @@
package io.embrace.android.embracesdk.fakes.behavior
import io.embrace.android.embracesdk.internal.config.behavior.LogMessageBehavior
+import io.embrace.android.embracesdk.internal.config.remote.LogRemoteConfig
class FakeLogMessageBehavior(
private val logMessageMaximumAllowedLength: Int = 128,
@@ -9,6 +10,11 @@ class FakeLogMessageBehavior(
private val errorLogLimit: Int = 100,
) : LogMessageBehavior {
+ override val local: Unit
+ get() = throw UnsupportedOperationException()
+ override val remote: LogRemoteConfig
+ get() = throw UnsupportedOperationException()
+
override fun getLogMessageMaximumAllowedLength(): Int = logMessageMaximumAllowedLength
override fun getInfoLogLimit(): Int = infoLogLimit
override fun getWarnLogLimit(): Int = warnLogLimit
diff --git a/embrace-test-fakes/src/main/kotlin/io/embrace/android/embracesdk/fakes/behavior/FakeNetworkBehavior.kt b/embrace-test-fakes/src/main/kotlin/io/embrace/android/embracesdk/fakes/behavior/FakeNetworkBehavior.kt
index 72efa1a25a..c49fb014a1 100644
--- a/embrace-test-fakes/src/main/kotlin/io/embrace/android/embracesdk/fakes/behavior/FakeNetworkBehavior.kt
+++ b/embrace-test-fakes/src/main/kotlin/io/embrace/android/embracesdk/fakes/behavior/FakeNetworkBehavior.kt
@@ -1,13 +1,21 @@
package io.embrace.android.embracesdk.fakes.behavior
import io.embrace.android.embracesdk.internal.config.behavior.NetworkBehavior
+import io.embrace.android.embracesdk.internal.config.instrumented.schema.InstrumentedConfig
import io.embrace.android.embracesdk.internal.config.remote.NetworkCaptureRuleRemoteConfig
+import io.embrace.android.embracesdk.internal.config.remote.RemoteConfig
class FakeNetworkBehavior(
private val captureLimit: Int = 1000,
private val domains: Map = emptyMap(),
private val captureHttpUrlConnectionRequests: Boolean = true,
) : NetworkBehavior {
+
+ override val local: InstrumentedConfig
+ get() = throw UnsupportedOperationException()
+ override val remote: RemoteConfig
+ get() = throw UnsupportedOperationException()
+
override fun isRequestContentLengthCaptureEnabled(): Boolean = false
override fun isHttpUrlConnectionCaptureEnabled(): Boolean = captureHttpUrlConnectionRequests
override fun getLimitsByDomain(): Map = domains
diff --git a/embrace-test-fakes/src/main/kotlin/io/embrace/android/embracesdk/fakes/behavior/FakeNetworkSpanForwardingBehavior.kt b/embrace-test-fakes/src/main/kotlin/io/embrace/android/embracesdk/fakes/behavior/FakeNetworkSpanForwardingBehavior.kt
index d9db1aec12..6648621f62 100644
--- a/embrace-test-fakes/src/main/kotlin/io/embrace/android/embracesdk/fakes/behavior/FakeNetworkSpanForwardingBehavior.kt
+++ b/embrace-test-fakes/src/main/kotlin/io/embrace/android/embracesdk/fakes/behavior/FakeNetworkSpanForwardingBehavior.kt
@@ -1,10 +1,17 @@
package io.embrace.android.embracesdk.fakes.behavior
import io.embrace.android.embracesdk.internal.config.behavior.NetworkSpanForwardingBehavior
+import io.embrace.android.embracesdk.internal.config.instrumented.schema.EnabledFeatureConfig
+import io.embrace.android.embracesdk.internal.config.remote.NetworkSpanForwardingRemoteConfig
class FakeNetworkSpanForwardingBehavior(
private val networkSpanForwardingEnabled: Boolean = false,
) : NetworkSpanForwardingBehavior {
+ override val local: EnabledFeatureConfig
+ get() = throw UnsupportedOperationException()
+ override val remote: NetworkSpanForwardingRemoteConfig
+ get() = throw UnsupportedOperationException()
+
override fun isNetworkSpanForwardingEnabled(): Boolean = networkSpanForwardingEnabled
}
diff --git a/embrace-test-fakes/src/main/kotlin/io/embrace/android/embracesdk/fakes/behavior/FakeSdkEndpointBehavior.kt b/embrace-test-fakes/src/main/kotlin/io/embrace/android/embracesdk/fakes/behavior/FakeSdkEndpointBehavior.kt
deleted file mode 100644
index 5752a15f88..0000000000
--- a/embrace-test-fakes/src/main/kotlin/io/embrace/android/embracesdk/fakes/behavior/FakeSdkEndpointBehavior.kt
+++ /dev/null
@@ -1,11 +0,0 @@
-package io.embrace.android.embracesdk.fakes.behavior
-
-import io.embrace.android.embracesdk.internal.config.behavior.SdkEndpointBehavior
-
-class FakeSdkEndpointBehavior(
- private val dataEndpoint: String,
- private val configEndpoint: String,
-) : SdkEndpointBehavior {
- override fun getData(appId: String?): String = dataEndpoint
- override fun getConfig(appId: String?): String = configEndpoint
-}
diff --git a/embrace-test-fakes/src/main/kotlin/io/embrace/android/embracesdk/fakes/behavior/FakeSdkModeBehavior.kt b/embrace-test-fakes/src/main/kotlin/io/embrace/android/embracesdk/fakes/behavior/FakeSdkModeBehavior.kt
index c0a281d6e3..6e202fb949 100644
--- a/embrace-test-fakes/src/main/kotlin/io/embrace/android/embracesdk/fakes/behavior/FakeSdkModeBehavior.kt
+++ b/embrace-test-fakes/src/main/kotlin/io/embrace/android/embracesdk/fakes/behavior/FakeSdkModeBehavior.kt
@@ -1,9 +1,16 @@
package io.embrace.android.embracesdk.fakes.behavior
import io.embrace.android.embracesdk.internal.config.behavior.SdkModeBehavior
+import io.embrace.android.embracesdk.internal.config.remote.RemoteConfig
class FakeSdkModeBehavior(
var sdkDisabled: Boolean,
) : SdkModeBehavior {
+
+ override val local: Unit
+ get() = throw UnsupportedOperationException()
+ override val remote: RemoteConfig
+ get() = throw UnsupportedOperationException()
+
override fun isSdkDisabled() = sdkDisabled
}
diff --git a/embrace-test-fakes/src/main/kotlin/io/embrace/android/embracesdk/fakes/behavior/FakeSessionBehavior.kt b/embrace-test-fakes/src/main/kotlin/io/embrace/android/embracesdk/fakes/behavior/FakeSessionBehavior.kt
index 4978a76cd1..bca5ca8d61 100644
--- a/embrace-test-fakes/src/main/kotlin/io/embrace/android/embracesdk/fakes/behavior/FakeSessionBehavior.kt
+++ b/embrace-test-fakes/src/main/kotlin/io/embrace/android/embracesdk/fakes/behavior/FakeSessionBehavior.kt
@@ -1,12 +1,19 @@
package io.embrace.android.embracesdk.fakes.behavior
import io.embrace.android.embracesdk.internal.config.behavior.SessionBehavior
+import io.embrace.android.embracesdk.internal.config.instrumented.schema.SessionConfig
+import io.embrace.android.embracesdk.internal.config.remote.RemoteConfig
class FakeSessionBehavior(
private val maxSessionProperties: Int = 100,
private val sessionControlEnabled: Boolean = false,
) : SessionBehavior {
+ override val local: SessionConfig
+ get() = throw UnsupportedOperationException()
+ override val remote: RemoteConfig
+ get() = throw UnsupportedOperationException()
+
override fun getFullSessionEvents(): Set = emptySet()
override fun getSessionComponents(): Set? = null
override fun isGatingFeatureEnabled(): Boolean = false
diff --git a/embrace-test-fakes/src/main/kotlin/io/embrace/android/embracesdk/fakes/behavior/FakeWebViewVitalsBehavior.kt b/embrace-test-fakes/src/main/kotlin/io/embrace/android/embracesdk/fakes/behavior/FakeWebViewVitalsBehavior.kt
index f51fc6e36b..bec80ba97d 100644
--- a/embrace-test-fakes/src/main/kotlin/io/embrace/android/embracesdk/fakes/behavior/FakeWebViewVitalsBehavior.kt
+++ b/embrace-test-fakes/src/main/kotlin/io/embrace/android/embracesdk/fakes/behavior/FakeWebViewVitalsBehavior.kt
@@ -1,12 +1,18 @@
package io.embrace.android.embracesdk.fakes.behavior
import io.embrace.android.embracesdk.internal.config.behavior.WebViewVitalsBehavior
+import io.embrace.android.embracesdk.internal.config.remote.RemoteConfig
class FakeWebViewVitalsBehavior(
private val maxWebViewVitals: Int = 100,
private val webViewVitalsEnabled: Boolean = true,
) : WebViewVitalsBehavior {
+ override val local: Unit
+ get() = throw UnsupportedOperationException()
+ override val remote: RemoteConfig
+ get() = throw UnsupportedOperationException()
+
override fun getMaxWebViewVitals(): Int = maxWebViewVitals
override fun isWebViewVitalsEnabled(): Boolean = webViewVitalsEnabled
}
diff --git a/embrace-test-fakes/src/main/kotlin/io/embrace/android/embracesdk/fakes/config/FakeBaseUrlConfig.kt b/embrace-test-fakes/src/main/kotlin/io/embrace/android/embracesdk/fakes/config/FakeBaseUrlConfig.kt
new file mode 100644
index 0000000000..e7eb30647d
--- /dev/null
+++ b/embrace-test-fakes/src/main/kotlin/io/embrace/android/embracesdk/fakes/config/FakeBaseUrlConfig.kt
@@ -0,0 +1,13 @@
+package io.embrace.android.embracesdk.fakes.config
+
+import io.embrace.android.embracesdk.internal.config.instrumented.InstrumentedConfigImpl
+import io.embrace.android.embracesdk.internal.config.instrumented.schema.BaseUrlConfig
+
+class FakeBaseUrlConfig(
+ base: BaseUrlConfig = InstrumentedConfigImpl.baseUrls,
+ private val configImpl: String? = base.getConfig(),
+ private val dataImpl: String? = base.getData(),
+) : BaseUrlConfig {
+ override fun getConfig(): String? = configImpl
+ override fun getData(): String? = dataImpl
+}
diff --git a/embrace-test-fakes/src/main/kotlin/io/embrace/android/embracesdk/fakes/config/FakeEnabledFeatureConfig.kt b/embrace-test-fakes/src/main/kotlin/io/embrace/android/embracesdk/fakes/config/FakeEnabledFeatureConfig.kt
new file mode 100644
index 0000000000..e6e93d59c8
--- /dev/null
+++ b/embrace-test-fakes/src/main/kotlin/io/embrace/android/embracesdk/fakes/config/FakeEnabledFeatureConfig.kt
@@ -0,0 +1,53 @@
+package io.embrace.android.embracesdk.fakes.config
+
+import io.embrace.android.embracesdk.internal.config.instrumented.InstrumentedConfigImpl
+import io.embrace.android.embracesdk.internal.config.instrumented.schema.EnabledFeatureConfig
+
+@Suppress("DEPRECATION")
+class FakeEnabledFeatureConfig(
+ base: EnabledFeatureConfig = InstrumentedConfigImpl.enabledFeatures,
+ private val unityAnrCapture: Boolean = base.isUnityAnrCaptureEnabled(),
+ private val activityBreadcrumbCapture: Boolean = base.isActivityBreadcrumbCaptureEnabled(),
+ private val composeClickCapture: Boolean = base.isComposeClickCaptureEnabled(),
+ private val viewClickCoordCapture: Boolean = base.isViewClickCoordinateCaptureEnabled(),
+ private val memoryWarningCapture: Boolean = base.isMemoryWarningCaptureEnabled(),
+ private val powerSaveCapture: Boolean = base.isPowerSaveModeCaptureEnabled(),
+ private val networkConnectivityCapture: Boolean = base.isNetworkConnectivityCaptureEnabled(),
+ private val anrCapture: Boolean = base.isAnrCaptureEnabled(),
+ private val diskUsageCapture: Boolean = base.isDiskUsageCaptureEnabled(),
+ private val jvmCrashCapture: Boolean = base.isJvmCrashCaptureEnabled(),
+ private val nativeCrashCapture: Boolean = base.isNativeCrashCaptureEnabled(),
+ private val aeiCapture: Boolean = base.isAeiCaptureEnabled(),
+ private val sigHandlerDetection: Boolean = base.is3rdPartySigHandlerDetectionEnabled(),
+ private val bgActivityCapture: Boolean = base.isBackgroundActivityCaptureEnabled(),
+ private val webviewBreadcrumbCapture: Boolean = base.isWebViewBreadcrumbCaptureEnabled(),
+ private val webviewQueryCapture: Boolean = base.isWebViewBreadcrumbQueryParamCaptureEnabled(),
+ private val fcmPiiCapture: Boolean = base.isFcmPiiDataCaptureEnabled(),
+ private val requestContentLengthCapture: Boolean = base.isRequestContentLengthCaptureEnabled(),
+ private val httpUrlConnectionCapture: Boolean = base.isHttpUrlConnectionCaptureEnabled(),
+ private val networkSpanForwarding: Boolean = base.isNetworkSpanForwardingEnabled(),
+) : EnabledFeatureConfig {
+
+ override fun isUnityAnrCaptureEnabled(): Boolean = unityAnrCapture
+ override fun isActivityBreadcrumbCaptureEnabled(): Boolean = activityBreadcrumbCapture
+ override fun isComposeClickCaptureEnabled(): Boolean = composeClickCapture
+ override fun isViewClickCoordinateCaptureEnabled(): Boolean = viewClickCoordCapture
+
+ @Deprecated("Will be removed in a future release.")
+ override fun isMemoryWarningCaptureEnabled(): Boolean = memoryWarningCapture
+ override fun isPowerSaveModeCaptureEnabled(): Boolean = powerSaveCapture
+ override fun isNetworkConnectivityCaptureEnabled(): Boolean = networkConnectivityCapture
+ override fun isAnrCaptureEnabled(): Boolean = anrCapture
+ override fun isDiskUsageCaptureEnabled(): Boolean = diskUsageCapture
+ override fun isJvmCrashCaptureEnabled(): Boolean = jvmCrashCapture
+ override fun isNativeCrashCaptureEnabled(): Boolean = nativeCrashCapture
+ override fun isAeiCaptureEnabled(): Boolean = aeiCapture
+ override fun is3rdPartySigHandlerDetectionEnabled(): Boolean = sigHandlerDetection
+ override fun isBackgroundActivityCaptureEnabled(): Boolean = bgActivityCapture
+ override fun isWebViewBreadcrumbCaptureEnabled(): Boolean = webviewBreadcrumbCapture
+ override fun isWebViewBreadcrumbQueryParamCaptureEnabled(): Boolean = webviewQueryCapture
+ override fun isFcmPiiDataCaptureEnabled(): Boolean = fcmPiiCapture
+ override fun isRequestContentLengthCaptureEnabled(): Boolean = requestContentLengthCapture
+ override fun isHttpUrlConnectionCaptureEnabled(): Boolean = httpUrlConnectionCapture
+ override fun isNetworkSpanForwardingEnabled(): Boolean = networkSpanForwarding
+}
diff --git a/embrace-test-fakes/src/main/kotlin/io/embrace/android/embracesdk/fakes/config/FakeInstrumentedConfig.kt b/embrace-test-fakes/src/main/kotlin/io/embrace/android/embracesdk/fakes/config/FakeInstrumentedConfig.kt
new file mode 100644
index 0000000000..d2b39df33a
--- /dev/null
+++ b/embrace-test-fakes/src/main/kotlin/io/embrace/android/embracesdk/fakes/config/FakeInstrumentedConfig.kt
@@ -0,0 +1,21 @@
+package io.embrace.android.embracesdk.fakes.config
+
+import io.embrace.android.embracesdk.internal.config.instrumented.InstrumentedConfigImpl
+import io.embrace.android.embracesdk.internal.config.instrumented.schema.InstrumentedConfig
+import io.embrace.android.embracesdk.internal.config.instrumented.schema.NetworkCaptureConfig
+import io.embrace.android.embracesdk.internal.config.instrumented.schema.ProjectConfig
+import io.embrace.android.embracesdk.internal.config.instrumented.schema.RedactionConfig
+import io.embrace.android.embracesdk.internal.config.instrumented.schema.SessionConfig
+
+/**
+ * A fake [InstrumentedConfig] implementation that defaults to the real implementation unless an override is supplied.
+ */
+data class FakeInstrumentedConfig(
+ private val base: InstrumentedConfig = InstrumentedConfigImpl,
+ override val baseUrls: FakeBaseUrlConfig = FakeBaseUrlConfig(base.baseUrls),
+ override val enabledFeatures: FakeEnabledFeatureConfig = FakeEnabledFeatureConfig(base.enabledFeatures),
+ override val networkCapture: NetworkCaptureConfig = FakeNetworkCaptureConfig(base.networkCapture),
+ override val project: ProjectConfig = FakeProjectConfig(base.project, appId = "abcde"),
+ override val redaction: RedactionConfig = FakeRedactionConfig(base.redaction),
+ override val session: SessionConfig = FakeSessionConfig(base.session),
+) : InstrumentedConfig
diff --git a/embrace-test-fakes/src/main/kotlin/io/embrace/android/embracesdk/fakes/config/FakeNetworkCaptureConfig.kt b/embrace-test-fakes/src/main/kotlin/io/embrace/android/embracesdk/fakes/config/FakeNetworkCaptureConfig.kt
new file mode 100644
index 0000000000..10564764fb
--- /dev/null
+++ b/embrace-test-fakes/src/main/kotlin/io/embrace/android/embracesdk/fakes/config/FakeNetworkCaptureConfig.kt
@@ -0,0 +1,17 @@
+package io.embrace.android.embracesdk.fakes.config
+
+import io.embrace.android.embracesdk.internal.config.instrumented.InstrumentedConfigImpl
+import io.embrace.android.embracesdk.internal.config.instrumented.schema.NetworkCaptureConfig
+
+class FakeNetworkCaptureConfig(
+ base: NetworkCaptureConfig = InstrumentedConfigImpl.networkCapture,
+ private val requestLimit: Int = base.getRequestLimitPerDomain(),
+ private val limits: Map = base.getLimitsByDomain(),
+ private val ignoredRequestPatterns: List = base.getIgnoredRequestPatternList(),
+ private val publicKey: String? = base.getNetworkBodyCapturePublicKey(),
+) : NetworkCaptureConfig {
+ override fun getRequestLimitPerDomain(): Int = requestLimit
+ override fun getLimitsByDomain(): Map = limits
+ override fun getIgnoredRequestPatternList(): List = ignoredRequestPatterns
+ override fun getNetworkBodyCapturePublicKey(): String? = publicKey
+}
diff --git a/embrace-test-fakes/src/main/kotlin/io/embrace/android/embracesdk/fakes/config/FakeProjectConfig.kt b/embrace-test-fakes/src/main/kotlin/io/embrace/android/embracesdk/fakes/config/FakeProjectConfig.kt
new file mode 100644
index 0000000000..8bf65d93fd
--- /dev/null
+++ b/embrace-test-fakes/src/main/kotlin/io/embrace/android/embracesdk/fakes/config/FakeProjectConfig.kt
@@ -0,0 +1,19 @@
+package io.embrace.android.embracesdk.fakes.config
+
+import io.embrace.android.embracesdk.internal.config.instrumented.InstrumentedConfigImpl
+import io.embrace.android.embracesdk.internal.config.instrumented.schema.ProjectConfig
+
+class FakeProjectConfig(
+ base: ProjectConfig = InstrumentedConfigImpl.project,
+ private val appId: String? = base.getAppId(),
+ private val appFramework: String? = base.getAppFramework(),
+ private val buildId: String? = base.getBuildId(),
+ private val buildType: String? = base.getBuildType(),
+ private val buildFlavor: String? = base.getBuildFlavor(),
+) : ProjectConfig {
+ override fun getAppId(): String? = appId
+ override fun getAppFramework(): String? = appFramework
+ override fun getBuildId(): String? = buildId
+ override fun getBuildType(): String? = buildType
+ override fun getBuildFlavor(): String? = buildFlavor
+}
diff --git a/embrace-test-fakes/src/main/kotlin/io/embrace/android/embracesdk/fakes/config/FakeRedactionConfig.kt b/embrace-test-fakes/src/main/kotlin/io/embrace/android/embracesdk/fakes/config/FakeRedactionConfig.kt
new file mode 100644
index 0000000000..0ec308725e
--- /dev/null
+++ b/embrace-test-fakes/src/main/kotlin/io/embrace/android/embracesdk/fakes/config/FakeRedactionConfig.kt
@@ -0,0 +1,11 @@
+package io.embrace.android.embracesdk.fakes.config
+
+import io.embrace.android.embracesdk.internal.config.instrumented.InstrumentedConfigImpl
+import io.embrace.android.embracesdk.internal.config.instrumented.schema.RedactionConfig
+
+class FakeRedactionConfig(
+ base: RedactionConfig = InstrumentedConfigImpl.redaction,
+ private val sensitiveKeys: List? = base.getSensitiveKeysDenylist(),
+) : RedactionConfig {
+ override fun getSensitiveKeysDenylist(): List? = sensitiveKeys
+}
diff --git a/embrace-test-fakes/src/main/kotlin/io/embrace/android/embracesdk/fakes/config/FakeSessionConfig.kt b/embrace-test-fakes/src/main/kotlin/io/embrace/android/embracesdk/fakes/config/FakeSessionConfig.kt
new file mode 100644
index 0000000000..c902b7fdbe
--- /dev/null
+++ b/embrace-test-fakes/src/main/kotlin/io/embrace/android/embracesdk/fakes/config/FakeSessionConfig.kt
@@ -0,0 +1,13 @@
+package io.embrace.android.embracesdk.fakes.config
+
+import io.embrace.android.embracesdk.internal.config.instrumented.InstrumentedConfigImpl
+import io.embrace.android.embracesdk.internal.config.instrumented.schema.SessionConfig
+
+class FakeSessionConfig(
+ base: SessionConfig = InstrumentedConfigImpl.session,
+ private val sessionComponentsImpl: List? = base.getSessionComponents(),
+ private val fullSessionEventsImpl: List = base.getFullSessionEvents(),
+) : SessionConfig {
+ override fun getSessionComponents(): List? = sessionComponentsImpl
+ override fun getFullSessionEvents(): List = fullSessionEventsImpl
+}
diff --git a/embrace-test-fakes/src/main/kotlin/io/embrace/android/embracesdk/fakes/injection/FakeEssentialServiceModule.kt b/embrace-test-fakes/src/main/kotlin/io/embrace/android/embracesdk/fakes/injection/FakeEssentialServiceModule.kt
index a93e288bf7..d9aa61f38d 100644
--- a/embrace-test-fakes/src/main/kotlin/io/embrace/android/embracesdk/fakes/injection/FakeEssentialServiceModule.kt
+++ b/embrace-test-fakes/src/main/kotlin/io/embrace/android/embracesdk/fakes/injection/FakeEssentialServiceModule.kt
@@ -3,7 +3,6 @@ package io.embrace.android.embracesdk.fakes.injection
import io.embrace.android.embracesdk.fakes.FakeActivityTracker
import io.embrace.android.embracesdk.fakes.FakeApiClient
import io.embrace.android.embracesdk.fakes.FakeApiService
-import io.embrace.android.embracesdk.fakes.FakeApiUrlBuilder
import io.embrace.android.embracesdk.fakes.FakeLogWriter
import io.embrace.android.embracesdk.fakes.FakeNetworkConnectivityService
import io.embrace.android.embracesdk.fakes.FakePendingApiCallsSender
@@ -16,7 +15,6 @@ import io.embrace.android.embracesdk.internal.capture.connectivity.NetworkConnec
import io.embrace.android.embracesdk.internal.capture.user.UserService
import io.embrace.android.embracesdk.internal.comms.api.ApiClient
import io.embrace.android.embracesdk.internal.comms.api.ApiService
-import io.embrace.android.embracesdk.internal.comms.api.ApiUrlBuilder
import io.embrace.android.embracesdk.internal.comms.delivery.PendingApiCallsSender
import io.embrace.android.embracesdk.internal.injection.EssentialServiceModule
import io.embrace.android.embracesdk.internal.session.id.SessionIdTracker
@@ -32,7 +30,6 @@ class FakeEssentialServiceModule(
override val apiService: ApiService = FakeApiService(),
override val networkConnectivityService: NetworkConnectivityService = FakeNetworkConnectivityService(),
override val pendingApiCallsSender: PendingApiCallsSender = FakePendingApiCallsSender(),
- override val urlBuilder: ApiUrlBuilder = FakeApiUrlBuilder(),
override val logWriter: LogWriter = FakeLogWriter(),
override val sessionPropertiesService: FakeSessionPropertiesService = FakeSessionPropertiesService(),
) : EssentialServiceModule
diff --git a/embrace-test-fakes/src/main/kotlin/io/embrace/android/embracesdk/fakes/injection/FakeInitModule.kt b/embrace-test-fakes/src/main/kotlin/io/embrace/android/embracesdk/fakes/injection/FakeInitModule.kt
index a0f142a21c..cc7ea9c2ec 100644
--- a/embrace-test-fakes/src/main/kotlin/io/embrace/android/embracesdk/fakes/injection/FakeInitModule.kt
+++ b/embrace-test-fakes/src/main/kotlin/io/embrace/android/embracesdk/fakes/injection/FakeInitModule.kt
@@ -2,8 +2,10 @@ package io.embrace.android.embracesdk.fakes.injection
import io.embrace.android.embracesdk.fakes.FakeClock
import io.embrace.android.embracesdk.fakes.FakeEmbLogger
+import io.embrace.android.embracesdk.fakes.config.FakeInstrumentedConfig
import io.embrace.android.embracesdk.internal.SystemInfo
import io.embrace.android.embracesdk.internal.clock.Clock
+import io.embrace.android.embracesdk.internal.config.instrumented.schema.InstrumentedConfig
import io.embrace.android.embracesdk.internal.injection.InitModule
import io.embrace.android.embracesdk.internal.injection.OpenTelemetryModule
import io.embrace.android.embracesdk.internal.injection.createInitModule
@@ -23,6 +25,7 @@ class FakeInitModule(
logger = logger,
systemInfo = systemInfo
),
+ override var instrumentedConfig: InstrumentedConfig = FakeInstrumentedConfig()
) : InitModule by initModule {
val openTelemetryModule: OpenTelemetryModule by lazy { createOpenTelemetryModule(initModule) }
diff --git a/embrace-test-fakes/src/main/kotlin/io/embrace/android/embracesdk/fakes/injection/FakeStorageModule.kt b/embrace-test-fakes/src/main/kotlin/io/embrace/android/embracesdk/fakes/injection/FakeStorageModule.kt
index b2434af92b..1880c133b8 100644
--- a/embrace-test-fakes/src/main/kotlin/io/embrace/android/embracesdk/fakes/injection/FakeStorageModule.kt
+++ b/embrace-test-fakes/src/main/kotlin/io/embrace/android/embracesdk/fakes/injection/FakeStorageModule.kt
@@ -3,7 +3,6 @@ package io.embrace.android.embracesdk.fakes.injection
import io.embrace.android.embracesdk.fakes.FakeCacheService
import io.embrace.android.embracesdk.fakes.FakeDeliveryCacheManager
import io.embrace.android.embracesdk.fakes.FakeStorageService
-import io.embrace.android.embracesdk.internal.comms.api.ApiResponseCache
import io.embrace.android.embracesdk.internal.comms.delivery.CacheService
import io.embrace.android.embracesdk.internal.comms.delivery.DeliveryCacheManager
import io.embrace.android.embracesdk.internal.injection.StorageModule
@@ -13,8 +12,4 @@ class FakeStorageModule(
override val cacheService: CacheService = FakeCacheService(),
override val deliveryCacheManager: DeliveryCacheManager = FakeDeliveryCacheManager(),
override val storageService: StorageService = FakeStorageService(),
-) : StorageModule {
-
- override val cache: ApiResponseCache
- get() = throw UnsupportedOperationException()
-}
+) : StorageModule