Skip to content

Commit

Permalink
fix: user agent client support in preferences repo
Browse files Browse the repository at this point in the history
  • Loading branch information
mrehan27 committed Oct 19, 2022
1 parent 317715a commit 454a18e
Show file tree
Hide file tree
Showing 12 changed files with 177 additions and 71 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ abstract class BaseTest {
protected lateinit var dateUtilStub: DateUtilStub

protected fun createConfig(
client: Client = Client.Android(sdkVersion = "1.0.0-alpha.6"),
client: Client = Client.fromRawValue(source = "AndroidTest", sdkVersion = "1.0.0-alpha.6"),
siteId: String = this.siteId,
apiKey: String = "xyz",
region: Region = Region.EU,
Expand Down
42 changes: 0 additions & 42 deletions sdk/api/sdk.api
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,6 @@ public final class io/customer/sdk/di/CustomerIOComponent : io/customer/sdk/di/D

public final class io/customer/sdk/di/CustomerIOSharedComponent : io/customer/sdk/di/DiGraph {
public fun <init> (Landroid/content/Context;)V
public final fun getSharedPreferenceRepository ()Lio/customer/sdk/repository/preference/SharedPreferenceRepository;
}

public final class io/customer/sdk/di/CustomerIOStaticComponent : io/customer/sdk/di/DiGraph {
Expand Down Expand Up @@ -325,47 +324,6 @@ public abstract interface class io/customer/sdk/repository/TrackRepository {
public abstract fun trackMetric (Ljava/lang/String;Lio/customer/sdk/data/request/MetricEvent;Ljava/lang/String;)V
}

public final class io/customer/sdk/repository/preference/CustomerIOStoredValues {
public static final field Companion Lio/customer/sdk/repository/preference/CustomerIOStoredValues$Companion;
public fun <init> (Lio/customer/sdk/CustomerIOConfig;)V
public fun <init> (Ljava/lang/String;Ljava/lang/String;Lio/customer/sdk/data/model/Region;Ljava/lang/String;ZLio/customer/sdk/util/CioLogLevel;ID)V
public synthetic fun <init> (Ljava/lang/String;Ljava/lang/String;Lio/customer/sdk/data/model/Region;Ljava/lang/String;ZLio/customer/sdk/util/CioLogLevel;IDILkotlin/jvm/internal/DefaultConstructorMarker;)V
public final fun component1 ()Ljava/lang/String;
public final fun component2 ()Ljava/lang/String;
public final fun component3 ()Lio/customer/sdk/data/model/Region;
public final fun component4 ()Ljava/lang/String;
public final fun component5 ()Z
public final fun component6 ()Lio/customer/sdk/util/CioLogLevel;
public final fun component7 ()I
public final fun component8 ()D
public final fun copy (Ljava/lang/String;Ljava/lang/String;Lio/customer/sdk/data/model/Region;Ljava/lang/String;ZLio/customer/sdk/util/CioLogLevel;ID)Lio/customer/sdk/repository/preference/CustomerIOStoredValues;
public static synthetic fun copy$default (Lio/customer/sdk/repository/preference/CustomerIOStoredValues;Ljava/lang/String;Ljava/lang/String;Lio/customer/sdk/data/model/Region;Ljava/lang/String;ZLio/customer/sdk/util/CioLogLevel;IDILjava/lang/Object;)Lio/customer/sdk/repository/preference/CustomerIOStoredValues;
public fun equals (Ljava/lang/Object;)Z
public final fun getApiKey ()Ljava/lang/String;
public final fun getAutoTrackDeviceAttributes ()Z
public final fun getBackgroundQueueMinNumberOfTasks ()I
public final fun getBackgroundQueueSecondsDelay ()D
public final fun getLogLevel ()Lio/customer/sdk/util/CioLogLevel;
public final fun getRegion ()Lio/customer/sdk/data/model/Region;
public final fun getSiteId ()Ljava/lang/String;
public final fun getTrackingApiUrl ()Ljava/lang/String;
public fun hashCode ()I
public fun toString ()Ljava/lang/String;
}

public final class io/customer/sdk/repository/preference/CustomerIOStoredValues$Companion {
public final fun getEmpty ()Lio/customer/sdk/repository/preference/CustomerIOStoredValues;
}

public final class io/customer/sdk/repository/preference/CustomerIOStoredValuesKt {
public static final fun doesExist (Lio/customer/sdk/repository/preference/CustomerIOStoredValues;)Z
}

public abstract interface class io/customer/sdk/repository/preference/SharedPreferenceRepository {
public abstract fun loadSettings ()Lio/customer/sdk/repository/preference/CustomerIOStoredValues;
public abstract fun saveSettings (Lio/customer/sdk/repository/preference/CustomerIOStoredValues;)V
}

public abstract interface class io/customer/sdk/repository/preference/SitePreferenceRepository {
public abstract fun clearAll ()V
public abstract fun getDeviceToken ()Ljava/lang/String;
Expand Down
1 change: 1 addition & 0 deletions sdk/src/main/java/io/customer/sdk/CustomerIO.kt
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ class CustomerIO internal constructor(
region = customerIOStoredValues.region,
appContext = context.applicationContext as Application
).apply {
setClient(client = customerIOStoredValues.client)
setLogLevel(level = customerIOStoredValues.logLevel)
customerIOStoredValues.trackingApiUrl?.let { setTrackingApiURL(trackingApiUrl = it) }
autoTrackDeviceAttributes(shouldTrackDeviceAttributes = customerIOStoredValues.autoTrackDeviceAttributes)
Expand Down
40 changes: 36 additions & 4 deletions sdk/src/main/java/io/customer/sdk/data/store/Client.kt
Original file line number Diff line number Diff line change
Expand Up @@ -16,26 +16,58 @@ sealed class Client(
/**
* Simpler class for Android clients.
*/
class Android(sdkVersion: String) : Client(source = "Android", sdkVersion = sdkVersion)
class Android(sdkVersion: String) : Client(source = SOURCE_ANDROID, sdkVersion = sdkVersion)

/**
* Simpler class for ReactNative clients.
*/
class ReactNative(sdkVersion: String) : Client(source = "ReactNative", sdkVersion = sdkVersion)
class ReactNative(sdkVersion: String) : Client(
source = SOURCE_REACT_NATIVE,
sdkVersion = sdkVersion
)

/**
* Simpler class for Expo clients.
*/
class Expo(sdkVersion: String) : Client(source = "Expo", sdkVersion = sdkVersion)
class Expo(sdkVersion: String) : Client(source = SOURCE_EXPO, sdkVersion = sdkVersion)

/**
* Other class to allow adding custom sources for clients that are not
* supported above.
* <p/>
* Use this only if the client platform is not available in the above list.
*/
class Other(
class Other internal constructor(
source: String,
sdkVersion: String
) : Client(source = source, sdkVersion = sdkVersion)

companion object {
internal const val SOURCE_ANDROID = "Android"
internal const val SOURCE_REACT_NATIVE = "ReactNative"
internal const val SOURCE_EXPO = "Expo"

/**
* Helper method to create client from raw values
*
* @param source raw string of client source (case insensitive)
* @param sdkVersion version of the SDK used
* @return [Client] created from provided values
*/
fun fromRawValue(source: String, sdkVersion: String): Client = when {
source.equals(
other = SOURCE_ANDROID,
ignoreCase = true
) -> Android(sdkVersion = sdkVersion)
source.equals(
other = SOURCE_REACT_NATIVE,
ignoreCase = true
) -> ReactNative(sdkVersion = sdkVersion)
source.equals(
other = SOURCE_EXPO,
ignoreCase = true
) -> Expo(sdkVersion = sdkVersion)
else -> Other(source = source, sdkVersion = sdkVersion)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import io.customer.sdk.repository.preference.SharedPreferenceRepositoryImp

class CustomerIOSharedComponent(context: Context) : DiGraph() {

val sharedPreferenceRepository: SharedPreferenceRepository by lazy {
internal val sharedPreferenceRepository: SharedPreferenceRepository by lazy {
override() ?: SharedPreferenceRepositoryImp(
context = context
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,16 @@ package io.customer.sdk.repository.preference
import io.customer.sdk.AnalyticsConstants
import io.customer.sdk.CustomerIOConfig
import io.customer.sdk.SDKConstants
import io.customer.sdk.Version
import io.customer.sdk.data.model.Region
import io.customer.sdk.data.store.Client
import io.customer.sdk.util.CioLogLevel

data class CustomerIOStoredValues(
internal data class CustomerIOStoredValues(
val siteId: String,
val apiKey: String,
val region: Region,
val client: Client = Client.Android(sdkVersion = Version.version),
val trackingApiUrl: String? = null,
val autoTrackDeviceAttributes: Boolean = AnalyticsConstants.AUTO_TRACK_DEVICE_ATTRIBUTES,
val logLevel: CioLogLevel = SDKConstants.LOG_LEVEL_DEFAULT,
Expand All @@ -20,6 +23,7 @@ data class CustomerIOStoredValues(
siteId = customerIOConfig.siteId,
apiKey = customerIOConfig.apiKey,
region = customerIOConfig.region,
client = customerIOConfig.client,
trackingApiUrl = customerIOConfig.trackingApiUrl,
autoTrackDeviceAttributes = customerIOConfig.autoTrackDeviceAttributes,
logLevel = customerIOConfig.logLevel,
Expand All @@ -36,4 +40,4 @@ data class CustomerIOStoredValues(
}
}

fun CustomerIOStoredValues.doesExist(): Boolean = this.siteId.isNotEmpty()
internal fun CustomerIOStoredValues.doesExist(): Boolean = this.siteId.isNotEmpty()
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
package io.customer.sdk.repository.preference

import android.content.Context
import io.customer.sdk.Version
import io.customer.sdk.data.store.Client
import io.customer.sdk.extensions.toRegion
import io.customer.sdk.extensions.valueOfOrNull
import io.customer.sdk.util.CioLogLevel

interface SharedPreferenceRepository {

internal interface SharedPreferenceRepository {
fun saveSettings(values: CustomerIOStoredValues)

fun loadSettings(): CustomerIOStoredValues
Expand All @@ -26,6 +27,8 @@ internal class SharedPreferenceRepositoryImp(context: Context) : SharedPreferenc
putString(SITE_ID, it.siteId)
putString(API_KEY, it.apiKey)
putString(REGION, it.region.code)
putString(CLIENT_SOURCE, it.client.source)
putString(CLIENT_SDK_VERSION, it.client.sdkVersion)
putString(TRACKING_API_URL, it.trackingApiUrl)
putBoolean(AUTO_TRACK_DEVICE_ATTRIBUTES, it.autoTrackDeviceAttributes)
putString(LOG_LEVEL, it.logLevel.name)
Expand All @@ -41,6 +44,10 @@ internal class SharedPreferenceRepositoryImp(context: Context) : SharedPreferenc
siteId = getString(SITE_ID, null).orEmpty(),
apiKey = getString(API_KEY, null).orEmpty(),
region = getString(REGION, null).toRegion(),
client = Client.fromRawValue(
source = getString(CLIENT_SOURCE, null) ?: "Unknown",
sdkVersion = getString(CLIENT_SDK_VERSION, null) ?: Version.version
),
trackingApiUrl = getString(TRACKING_API_URL, null),
autoTrackDeviceAttributes = getBoolean(AUTO_TRACK_DEVICE_ATTRIBUTES, true),
logLevel = getString(LOG_LEVEL, null)?.let { valueOfOrNull<CioLogLevel>(it) }
Expand All @@ -58,6 +65,8 @@ internal class SharedPreferenceRepositoryImp(context: Context) : SharedPreferenc
const val SITE_ID = "siteId"
const val API_KEY = "apiKey"
const val REGION = "region"
const val CLIENT_SOURCE = "clientSource"
const val CLIENT_SDK_VERSION = "clientSdkVersion"

const val TRACKING_API_URL = "trackingApiUrl"
const val AUTO_TRACK_DEVICE_ATTRIBUTES = "autoTrackDeviceAttributes"
Expand Down
35 changes: 19 additions & 16 deletions sdk/src/sharedTest/java/io/customer/sdk/CustomerIOTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import io.customer.sdk.repository.preference.SharedPreferenceRepository
import kotlinx.coroutines.runBlocking
import org.amshove.kluent.shouldBe
import org.amshove.kluent.shouldBeEqualTo
import org.amshove.kluent.shouldNotBe
import org.amshove.kluent.shouldNotBeNull
import org.junit.Before
import org.junit.Test
Expand Down Expand Up @@ -188,10 +189,9 @@ class CustomerIOTest : BaseTest() {
val diGraph = CustomerIOStaticComponent()
val diIOSharedComponent = CustomerIOSharedComponent(context)

val sharedPreferenceRepository: SharedPreferenceRepository =
mock<SharedPreferenceRepository>().apply {
whenever(this.loadSettings()).thenReturn(CustomerIOStoredValues.empty)
}
val sharedPreferenceRepository = mock<SharedPreferenceRepository>().apply {
whenever(this.loadSettings()).thenReturn(CustomerIOStoredValues.empty)
}
diIOSharedComponent.overrideDependency(
SharedPreferenceRepository::class.java,
sharedPreferenceRepository
Expand All @@ -212,10 +212,9 @@ class CustomerIOTest : BaseTest() {
val diGraph = CustomerIOStaticComponent()
val diIOSharedComponent = CustomerIOSharedComponent(context)

val sharedPreferenceRepository: SharedPreferenceRepository =
mock<SharedPreferenceRepository>().apply {
whenever(this.loadSettings()).thenReturn(CustomerIOStoredValues(cioConfig))
}
val sharedPreferenceRepository = mock<SharedPreferenceRepository>().apply {
whenever(this.loadSettings()).thenReturn(CustomerIOStoredValues(cioConfig))
}
diIOSharedComponent.overrideDependency(
SharedPreferenceRepository::class.java,
sharedPreferenceRepository
Expand All @@ -225,14 +224,18 @@ class CustomerIOTest : BaseTest() {
instance.diSharedGraph = diIOSharedComponent

val customerIO = CustomerIO.instanceOrNull(context)
customerIO?.diGraph?.sdkConfig?.siteId shouldBeEqualTo cioConfig.siteId
customerIO?.diGraph?.sdkConfig?.apiKey shouldBeEqualTo cioConfig.apiKey
customerIO?.diGraph?.sdkConfig?.region shouldBeEqualTo cioConfig.region
customerIO?.diGraph?.sdkConfig?.trackingApiUrl shouldBeEqualTo cioConfig.trackingApiUrl
customerIO?.diGraph?.sdkConfig?.autoTrackDeviceAttributes shouldBeEqualTo cioConfig.autoTrackDeviceAttributes
customerIO?.diGraph?.sdkConfig?.logLevel shouldBeEqualTo cioConfig.logLevel
customerIO?.diGraph?.sdkConfig?.backgroundQueueMinNumberOfTasks shouldBeEqualTo cioConfig.backgroundQueueMinNumberOfTasks
customerIO?.diGraph?.sdkConfig?.backgroundQueueSecondsDelay shouldBeEqualTo cioConfig.backgroundQueueSecondsDelay
customerIO shouldNotBe null

val sdkConfig = customerIO!!.diGraph.sdkConfig
sdkConfig.siteId shouldBeEqualTo cioConfig.siteId
sdkConfig.apiKey shouldBeEqualTo cioConfig.apiKey
sdkConfig.region shouldBeEqualTo cioConfig.region
sdkConfig.client.toString() shouldBeEqualTo cioConfig.client.toString()
sdkConfig.trackingApiUrl shouldBeEqualTo cioConfig.trackingApiUrl
sdkConfig.autoTrackDeviceAttributes shouldBeEqualTo cioConfig.autoTrackDeviceAttributes
sdkConfig.logLevel shouldBeEqualTo cioConfig.logLevel
sdkConfig.backgroundQueueMinNumberOfTasks shouldBeEqualTo cioConfig.backgroundQueueMinNumberOfTasks
sdkConfig.backgroundQueueSecondsDelay shouldBeEqualTo cioConfig.backgroundQueueSecondsDelay
}

private fun getRandomCustomerIOBuilder(): CustomerIO.Builder = CustomerIO.Builder(
Expand Down
54 changes: 53 additions & 1 deletion sdk/src/sharedTest/java/io/customer/sdk/data/store/ClientTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,60 @@ class ClientTest : BaseTest() {

@Test
fun initialize_givenOther_expectOtherClient() {
val iOSClient = Client.Other(source = "iOS", sdkVersion = "4.6.7")
val iOSClient = Client.fromRawValue(source = "iOS", sdkVersion = "4.6.7")

iOSClient.toString().shouldBeEqualTo(expected = "iOS Client/4.6.7")
}

@Test
fun initialize_givenRawValueAndroid_expectAndroidClient() {
val lowerCaseClient = Client.fromRawValue(source = "android", sdkVersion = "1.2.3")
val upperCaseClient = Client.fromRawValue(source = "ANDROID", sdkVersion = "2.3.4")
val titleCaseClient = Client.fromRawValue(source = "Android", sdkVersion = "3.4.5")
val mixedCaseClient = Client.fromRawValue(source = "AndRoid", sdkVersion = "4.5.6")

lowerCaseClient.toString().shouldBeEqualTo(expected = "Android Client/1.2.3")
upperCaseClient.toString().shouldBeEqualTo(expected = "Android Client/2.3.4")
titleCaseClient.toString().shouldBeEqualTo(expected = "Android Client/3.4.5")
mixedCaseClient.toString().shouldBeEqualTo(expected = "Android Client/4.5.6")
}

@Test
fun initialize_givenRawValueReactNative_expectReactNativeClient() {
val lowerCaseClient = Client.fromRawValue(source = "reactnative", sdkVersion = "1.2.3")
val upperCaseClient = Client.fromRawValue(source = "REACTNATIVE", sdkVersion = "2.3.4")
val titleCaseClient = Client.fromRawValue(source = "ReactNative", sdkVersion = "3.4.5")
val mixedCaseClient = Client.fromRawValue(source = "REACTNative", sdkVersion = "4.5.6")

lowerCaseClient.toString().shouldBeEqualTo(expected = "ReactNative Client/1.2.3")
upperCaseClient.toString().shouldBeEqualTo(expected = "ReactNative Client/2.3.4")
titleCaseClient.toString().shouldBeEqualTo(expected = "ReactNative Client/3.4.5")
mixedCaseClient.toString().shouldBeEqualTo(expected = "ReactNative Client/4.5.6")
}

@Test
fun initialize_givenRawValueExpo_expectExpoClient() {
val lowerCaseClient = Client.fromRawValue(source = "expo", sdkVersion = "1.2.3")
val upperCaseClient = Client.fromRawValue(source = "EXPO", sdkVersion = "2.3.4")
val titleCaseClient = Client.fromRawValue(source = "Expo", sdkVersion = "3.4.5")
val mixedCaseClient = Client.fromRawValue(source = "ExpO", sdkVersion = "4.5.6")

lowerCaseClient.toString().shouldBeEqualTo(expected = "Expo Client/1.2.3")
upperCaseClient.toString().shouldBeEqualTo(expected = "Expo Client/2.3.4")
titleCaseClient.toString().shouldBeEqualTo(expected = "Expo Client/3.4.5")
mixedCaseClient.toString().shouldBeEqualTo(expected = "Expo Client/4.5.6")
}

@Test
fun initialize_givenRawValueOther_expectOtherClient() {
val lowerCaseClient = Client.fromRawValue(source = "ios", sdkVersion = "1.2.3")
val upperCaseClient = Client.fromRawValue(source = "IOS", sdkVersion = "2.3.4")
val titleCaseClient = Client.fromRawValue(source = "Ios", sdkVersion = "3.4.5")
val mixedCaseClient = Client.fromRawValue(source = "iOS", sdkVersion = "4.5.6")

lowerCaseClient.toString().shouldBeEqualTo(expected = "ios Client/1.2.3")
upperCaseClient.toString().shouldBeEqualTo(expected = "IOS Client/2.3.4")
titleCaseClient.toString().shouldBeEqualTo(expected = "Ios Client/3.4.5")
mixedCaseClient.toString().shouldBeEqualTo(expected = "iOS Client/4.5.6")
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ class DeviceStoreTest : BaseTest() {
@Test
fun verifyUseragentIsCreatedCorrectly() {
deviceStore.buildUserAgent() shouldBeEqualTo
"Customer.io Android Client/1.0.0-alpha.6 (Google Pixel 6; 30) io.customer.sdk/1.0"
"Customer.io AndroidTest Client/1.0.0-alpha.6 (Google Pixel 6; 30) io.customer.sdk/1.0"
}

@Test
Expand Down
Loading

0 comments on commit 454a18e

Please sign in to comment.