Skip to content

Commit

Permalink
RUM-5525 Add the integration tests for the SdkCore APIs
Browse files Browse the repository at this point in the history
  • Loading branch information
mariusc83 committed Jul 31, 2024
1 parent a7492b5 commit 5eba221
Show file tree
Hide file tree
Showing 13 changed files with 541 additions and 24 deletions.
2 changes: 2 additions & 0 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ espresso = "3.5.1"
assertJ = "3.18.1"
elmyr = "1.3.1"
mockitoKotlin = "5.1.0"
mockitoAndroid = "5.12.0"
kover = "0.7.6"
kspTesting = "1.5.0"

Expand Down Expand Up @@ -175,6 +176,7 @@ elmyrInject = { module = "com.github.xgouchet.Elmyr:inject", version.ref = "elmy
elmyrJUnit4 = { module = "com.github.xgouchet.Elmyr:junit4", version.ref = "elmyr" }
elmyrJUnit5 = { module = "com.github.xgouchet.Elmyr:junit5", version.ref = "elmyr" }
elmyrJVM = { module = "com.github.xgouchet.Elmyr:jvm", version.ref = "elmyr" }
mockitoAndroid = { module = "org.mockito:mockito-android", version.ref = "mockitoAndroid" }
mockitoKotlin = { module = "org.mockito.kotlin:mockito-kotlin", version.ref = "mockitoKotlin" }
kotlinReflect = { module = "org.jetbrains.kotlin:kotlin-reflect", version.ref = "kotlin" }
kover = { module = "org.jetbrains.kotlinx:kover-gradle-plugin", version.ref = "kover" }
Expand Down
68 changes: 52 additions & 16 deletions reliability/core-it/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@
* Copyright 2016-Present Datadog, Inc.
*/

import com.datadog.gradle.config.AndroidConfig
import com.datadog.gradle.config.androidLibraryConfig
import com.datadog.gradle.config.dependencyUpdateConfig
import com.datadog.gradle.config.java17
import com.datadog.gradle.config.javadocConfig
import com.datadog.gradle.config.junitConfig
import com.datadog.gradle.config.kotlinConfig
Expand All @@ -26,10 +28,43 @@ plugins {

android {
namespace = "com.datadog.android.core.integration"
defaultConfig {
minSdk = AndroidConfig.MIN_SDK
multiDexEnabled = true
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
}

compileOptions {
java17()
}

packaging {
resources {
excludes += listOf(
"META-INF/jvm.kotlin_module",
"META-INF/LICENSE.md",
"META-INF/LICENSE-notice.md"
)
}
}

sourceSets.named("test") {
// Required because AGP doesn't support kotlin test fixtures :/
java.srcDir("${project.rootDir.path}/dd-sdk-android-core/src/testFixtures/kotlin")
buildTypes {
getByName("release") {
isMinifyEnabled = true
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
testProguardFile("test-proguard-rules.pro")
}
getByName("debug") {
isMinifyEnabled = true
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
testProguardFile("test-proguard-rules.pro")
}
}
}

Expand All @@ -38,25 +73,26 @@ dependencies {
implementation(libs.kotlin)

// Testing
testImplementation(project(":tools:unit")) {
androidTestImplementation(project(":tools:unit")) {
attributes {
attribute(
com.android.build.api.attributes.ProductFlavorAttr.of("platform"),
objects.named("jvm")
objects.named("art")
)
}
}
testImplementation(testFixtures(project(":dd-sdk-android-core")))
testImplementation(libs.bundles.jUnit5)
testImplementation(libs.bundles.testTools)
testImplementation(libs.okHttp)
testImplementation(libs.gson)
unmock(libs.robolectric)
}

unMock {
keepStartingWith("android.os")
keepStartingWith("org.json")
androidTestImplementation(project(":reliability:stub-feature"))
androidTestImplementation(libs.assertJ)
androidTestImplementation(libs.mockitoAndroid)
androidTestImplementation(libs.bundles.integrationTests)
androidTestImplementation(libs.elmyrJVM)
androidTestImplementation(libs.okHttp)
androidTestImplementation(libs.okHttpMock)
androidTestImplementation(libs.gson)
if (project.hasProperty(com.datadog.gradle.Properties.USE_API21_JAVA_BACKPORT)) {
// this is needed to make AssertJ working on APIs <24
androidTestImplementation(project(":tools:javabackport"))
}
}

androidLibraryConfig()
Expand Down
7 changes: 7 additions & 0 deletions reliability/core-it/proguard-rules.pro
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Needed to make sure we don't remove any test code
-dontshrink
#-dontoptimize
#-keepattributes *Annotation*

-dontwarn kotlin.Experimental$Level
-dontwarn kotlin.Experimental
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
/*
* Unless explicitly stated otherwise all files in this repository are licensed under the Apache License Version 2.0.
* This product includes software developed at Datadog (https://www.datadoghq.com/).
* Copyright 2016-Present Datadog, Inc.
*/

package com.datadog.android.core.integration

import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.datadog.android.Datadog
import com.datadog.android.api.context.UserInfo
import com.datadog.android.api.feature.FeatureSdkCore
import com.datadog.android.api.feature.StorageBackedFeature
import com.datadog.android.api.feature.stub.StubStorageBackedFeature
import com.datadog.android.core.configuration.Configuration
import com.datadog.android.core.integration.tests.MockServerTest
import com.datadog.android.core.integration.tests.forge.factories.ConfigurationCoreForgeryFactory
import com.datadog.android.privacy.TrackingConsent
import com.datadog.tools.unit.ConditionWatcher
import com.datadog.tools.unit.forge.exhaustiveAttributes
import com.datadog.tools.unit.forge.useToolsFactories
import fr.xgouchet.elmyr.annotation.StringForgery
import fr.xgouchet.elmyr.annotation.StringForgeryType
import fr.xgouchet.elmyr.junit4.ForgeRule
import fr.xgouchet.elmyr.jvm.useJvmFactories
import org.assertj.core.api.Assertions.assertThat
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith

@RunWith(AndroidJUnit4::class)
class SdkCoreTest : MockServerTest() {

@get:Rule
var forge = ForgeRule().useJvmFactories().useToolsFactories().withFactory(ConfigurationCoreForgeryFactory())

@StringForgery(type = StringForgeryType.ALPHABETICAL)
lateinit var fakeUserId: String

@StringForgery(regex = "[A-Z][a-z]+ [A-Z]\\. [A-Z][a-z]+")
lateinit var fakeUserName: String

@StringForgery(regex = "[a-z]+\\.[a-z]+@[a-z]+\\.[a-z]{3}")
lateinit var fakeUserEmail: String
private var fakeUserAdditionalProperties: Map<String, Any?> = emptyMap()
private lateinit var stubFeature: StorageBackedFeature

@StringForgery(type = StringForgeryType.ALPHABETICAL)
lateinit var fakeFeatureName: String

@Before
fun setUp() {
stubFeature = StubStorageBackedFeature(
forge,
fakeFeatureName,
getMockServerWrapper().getServerUrl()
)
fakeUserAdditionalProperties = forge.exhaustiveAttributes(excludedKeys = setOf("id", "name", "email"))
}

// region set UserInfo

@Test
fun must_addUserInformationIntoEvents_when_setUserInformation() {
// Given
val configuration: Configuration = forge.getForgery()
val sdkCore = Datadog.initialize(
ApplicationProvider.getApplicationContext(),
configuration,
forge.aValueFrom(TrackingConsent::class.java)
)
val featureSdkCore = sdkCore as? FeatureSdkCore
featureSdkCore?.registerFeature(stubFeature)

// When
sdkCore?.setUserInfo(fakeUserId, fakeUserName, fakeUserEmail, fakeUserAdditionalProperties)

// Then
var readUserInfo: UserInfo? = null
ConditionWatcher {
featureSdkCore?.getFeature(stubFeature.name)?.withWriteContext { datadogContext, _ ->
readUserInfo = datadogContext.userInfo
}
assertThat(readUserInfo?.id).isEqualTo(fakeUserId)
assertThat(readUserInfo?.name).isEqualTo(fakeUserName)
assertThat(readUserInfo?.email).isEqualTo(fakeUserEmail)
assertThat(readUserInfo?.additionalProperties)
.containsExactlyInAnyOrderEntriesOf(fakeUserAdditionalProperties)
true
}.doWait(timeoutMs = SHORT_WAIT_MS)
}

// endregion

// region add User Properties

@Test
fun must_addUserExtraProperties_when_addUserProperties() {
// Given
val configuration: Configuration = forge.getForgery()
val sdkCore = Datadog.initialize(
ApplicationProvider.getApplicationContext(),
configuration,
forge.aValueFrom(TrackingConsent::class.java)
)
val featureSdkCore = sdkCore as? FeatureSdkCore
featureSdkCore?.registerFeature(stubFeature)
sdkCore?.setUserInfo(fakeUserId, fakeUserName, fakeUserEmail, fakeUserAdditionalProperties)
val expectedUserExtraProperties = forge.exhaustiveAttributes()

// When
sdkCore?.addUserProperties(expectedUserExtraProperties)

// Then
var readUserInfo: UserInfo? = null
ConditionWatcher {
featureSdkCore?.getFeature(stubFeature.name)?.withWriteContext { datadogContext, _ ->
readUserInfo = datadogContext.userInfo
}
assertThat(readUserInfo?.id).isEqualTo(fakeUserId)
assertThat(readUserInfo?.name).isEqualTo(fakeUserName)
assertThat(readUserInfo?.email).isEqualTo(fakeUserEmail)
assertThat(readUserInfo?.additionalProperties)
.containsExactlyInAnyOrderEntriesOf(fakeUserAdditionalProperties + expectedUserExtraProperties)
true
}.doWait(timeoutMs = SHORT_WAIT_MS)
}

// endregion

// region set Tracking Consent

@Test
fun must_updateTrackingConsent_when_setTrackingConsent() {
// Given
val configuration: Configuration = forge.getForgery()
val expectedTrackingConsent = forge.aValueFrom(TrackingConsent::class.java)
val sdkCore = Datadog.initialize(
ApplicationProvider.getApplicationContext(),
configuration,
forge.aValueFrom(TrackingConsent::class.java)
)
val featureSdkCore = sdkCore as? FeatureSdkCore
featureSdkCore?.registerFeature(stubFeature)

// When
sdkCore?.setTrackingConsent(expectedTrackingConsent)

// Then
var trackingConsent: TrackingConsent? = null
ConditionWatcher {
featureSdkCore?.getFeature(stubFeature.name)?.withWriteContext { datadogContext, _ ->
trackingConsent = datadogContext.trackingConsent
}
assertThat(trackingConsent).isEqualTo(expectedTrackingConsent)
true
}.doWait(timeoutMs = SHORT_WAIT_MS)
}

// endregion
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/*
* Unless explicitly stated otherwise all files in this repository are licensed under the Apache License Version 2.0.
* This product includes software developed at Datadog (https://www.datadoghq.com/).
* Copyright 2016-Present Datadog, Inc.
*/

package com.datadog.android.core.integration.tests

import java.util.concurrent.TimeUnit

@Suppress("UtilityClassWithPublicConstructor")
abstract class BaseTest {

companion object {
internal val LONG_WAIT_MS = TimeUnit.SECONDS.toMillis(30)
internal const val SHORT_WAIT_MS = 500L
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
* Unless explicitly stated otherwise all files in this repository are licensed under the Apache License Version 2.0.
* This product includes software developed at Datadog (https://www.datadoghq.com/).
* Copyright 2016-Present Datadog, Inc.
*/

package com.datadog.android.core.integration.tests

import com.datadog.android.core.integration.tests.utils.MockWebServerWrapper
import org.junit.AfterClass
import org.junit.BeforeClass
import java.util.concurrent.atomic.AtomicBoolean

abstract class MockServerTest : BaseTest() {

fun getMockServerWrapper(): MockWebServerWrapper {
return mockServerWrapper
}

companion object {
private val mockServerStarted = AtomicBoolean(false)
protected val mockServerWrapper: MockWebServerWrapper = MockWebServerWrapper()

@BeforeClass
@JvmStatic
fun setupTestSuite() {
if (mockServerStarted.compareAndSet(false, true)) {
mockServerWrapper.start()
}
}

@AfterClass
@JvmStatic
fun tearDown() {
if (mockServerStarted.compareAndSet(true, false)) {
mockServerWrapper.shutdown()
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/*
* Unless explicitly stated otherwise all files in this repository are licensed under the Apache License Version 2.0.
* This product includes software developed at Datadog (https://www.datadoghq.com/).
* Copyright 2016-Present Datadog, Inc.
*/

package com.datadog.android.core.integration.tests.forge.factories

import com.datadog.android.DatadogSite
import com.datadog.android._InternalProxy
import com.datadog.android.core.configuration.Configuration
import com.datadog.android.trace.TracingHeaderType
import fr.xgouchet.elmyr.Forge
import fr.xgouchet.elmyr.ForgeryFactory
import java.util.UUID

internal class ConfigurationCoreForgeryFactory :
ForgeryFactory<Configuration> {
override fun getForgery(forge: Forge): Configuration {
return Configuration.Builder(
UUID.randomUUID().toString(),
forge.anHexadecimalString(),
forge.anHexadecimalString(),
forge.aNullable {
anAlphaNumericalString()
}
)
.setUseDeveloperModeWhenDebuggable(forge.aBool())
.setFirstPartyHostsWithHeaderType(
forge.aMap {
val fakeUrl = forge.aStringMatching("https://[a-z0-9]+\\.com")
fakeUrl to aList {
aValueFrom(
TracingHeaderType::class.java
)
}.toSet()
}
)
.apply {
_InternalProxy.allowClearTextHttp(this)
}
.setBatchSize(forge.getForgery())
.setUploadFrequency(forge.getForgery())
.useSite(forge.aValueFrom(DatadogSite::class.java))
.build()
}
}
Loading

0 comments on commit 5eba221

Please sign in to comment.