Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RUM-5525 Add the integration tests for the SdkCore APIs #2145

Merged

Conversation

mariusc83
Copy link
Member

@mariusc83 mariusc83 commented Jul 26, 2024

What does this PR do?

In this PR we are adding the integrations tests to cover the SdkCore public API. In addition to that we are introducing the StubStorageBackedFeature which will be leveraged in order to assert expected behaviours of the core module during the integration tests.

Motivation

What inspired you to submit this pull request?

Additional Notes

Anything else we should know when reviewing?

Review checklist (to be filled by reviewers)

  • Feature or bugfix MUST have appropriate tests (unit, integration, e2e)
  • Make sure you discussed the feature or bugfix with the maintaining team in an Issue
  • Make sure each commit and the PR mention the Issue number (cf the CONTRIBUTING doc)

@mariusc83 mariusc83 self-assigned this Jul 26, 2024
@mariusc83 mariusc83 force-pushed the mconstantin/rum-5525/add-integration-tests-for-sdkcore branch from b1cc80f to 89364ed Compare July 26, 2024 12:26
@mariusc83 mariusc83 marked this pull request as ready for review July 26, 2024 12:29
@mariusc83 mariusc83 requested review from a team as code owners July 26, 2024 12:29
@codecov-commenter
Copy link

codecov-commenter commented Jul 26, 2024

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 70.03%. Comparing base (405b9b4) to head (ed62d5f).

Additional details and impacted files
@@             Coverage Diff             @@
##           develop    #2145      +/-   ##
===========================================
+ Coverage    69.98%   70.03%   +0.05%     
===========================================
  Files          726      726              
  Lines        27001    26996       -5     
  Branches      4525     4524       -1     
===========================================
+ Hits         18895    18904       +9     
+ Misses        6836     6829       -7     
+ Partials      1270     1263       -7     

see 25 files with indirect coverage changes

Comment on lines +51 to +67
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")
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note

Why do you need a release build, and why minify both release and debug ?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am trying to test these in the same conditions as a normal app. We did the same for integration tests. Not sure is the best approach but I think it is better.

Comment on lines 37 to 42
private var fakeUserId: String? = null
private var fakeUserName: String? = null
private var fakeUserEmail: String? = null
private var fakeUserAdditionalProperties: Map<String, Any?> = emptyMap()
private lateinit var stubFeature: StorageBackedFeature
private lateinit var fakeFeatureName: String
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note

The @[…]Forgery annotations work in JUnit4 too, so you could use that instead of manual forgeries in the setUp() method.

class SdkCoreTest : MockServerTest() {

@get:Rule
var forge = ForgeRule()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
var forge = ForgeRule()
var forge = ForgeRule()
.useJvmFactories()
.useToolsFactories()
.withFactory(ConfigurationCoreForgeryFactory()

Comment on lines 77 to 88
ConditionWatcher {
var readUserInfo: UserInfo? = null
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 = FINAL_WAIT_MS)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Important

Is a 30 seconds wait really necessary here ? We're not writing anything to disk, and this could hide a problem if setting the user info actually gets delayed more than acceptable amount of time.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it is max 30 seconds, same approach we have in the integration tests now. I am not actually sure we are not writing on disk as the UserInfoProvider writes on the disk first. I am going to check if we use also the RAM in addition to that for the current process.

assertThat(readUserInfo?.additionalProperties)
.containsExactlyInAnyOrderEntriesOf(fakeUserAdditionalProperties + expectedUserExtraProperties)
true
}.doWait(timeoutMs = FINAL_WAIT_MS)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here

assertThat(datadogContext.trackingConsent).isEqualTo(expectedTrackingConsent)
}
true
}.doWait(timeoutMs = FINAL_WAIT_MS)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here

@mariusc83 mariusc83 force-pushed the mconstantin/rum-5525/add-integration-tests-for-sdkcore branch from 89364ed to f9a4c8e Compare July 29, 2024 12:07
@mariusc83 mariusc83 requested a review from xgouchet July 29, 2024 12:07
@mariusc83 mariusc83 force-pushed the mconstantin/rum-5525/add-integration-tests-for-sdkcore branch 3 times, most recently from 5eba221 to 07b92b7 Compare July 31, 2024 09:44
abstract class BaseTest {

companion object {
internal val LONG_WAIT_MS = TimeUnit.SECONDS.toMillis(30)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see this being used anywhere anymore. Can it be removed?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I might use it later as some use - cases will require it (waiting for messages to be send through mock server). I would rather keep fit for now and decide later.

Comment on lines 69 to 76
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)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note

Shouldn't this be part of the setup?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yup we could add it there

Comment on lines 82 to 93
val countDownLatch = CountDownLatch(1)
var readUserInfo: UserInfo? = null
featureSdkCore?.getFeature(stubFeature.name)?.withWriteContext { datadogContext, _ ->
readUserInfo = datadogContext.userInfo
countDownLatch.countDown()
}
countDownLatch.await(SHORT_WAIT_MS, TimeUnit.MILLISECONDS)
assertThat(readUserInfo?.id).isEqualTo(fakeUserId)
assertThat(readUserInfo?.name).isEqualTo(fakeUserName)
assertThat(readUserInfo?.email).isEqualTo(fakeUserEmail)
assertThat(readUserInfo?.additionalProperties)
.containsExactlyInAnyOrderEntriesOf(fakeUserAdditionalProperties)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 Much Better

// region add User Properties

@Test
fun must_addUserExtraProperties_when_addUserProperties() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note

You need another test when you don't call setUserInfo first, and probably another ones where you overwrite values too (both overriding a value set from setUserInfo and a value set from addUserProperties.

// region set Tracking Consent

@Test
fun must_updateTrackingConsent_when_setTrackingConsent() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note

You need another test to verify that the value you get is the one from initialize when you don't update it.

import java.util.concurrent.TimeUnit

@RunWith(AndroidJUnit4::class)
class SdkCoreTest : MockServerTest() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note

To make tests easier, we can split the core test by scopes, and name the test classes accordingly

  • SdkCoreInformation (not really sure about the name here) for the current one, to test data that's kept in memory (user info, global attributes, tracking consent, …) used by features
  • SdkCoreIO (maybe with variants based on Tracking consent: …Granted, …Denied, …Pending, …PendingToGranted, …PendingToDenied, …) to test that data sent to the core is dealt with accordingly
  • … ?

@mariusc83 mariusc83 force-pushed the mconstantin/rum-5525/add-integration-tests-for-sdkcore branch 2 times, most recently from def6157 to 85fb24b Compare August 2, 2024 11:56
@mariusc83 mariusc83 force-pushed the mconstantin/rum-5525/add-integration-tests-for-sdkcore branch from 85fb24b to ed62d5f Compare August 2, 2024 11:57
@mariusc83 mariusc83 requested a review from xgouchet August 2, 2024 12:04
private lateinit var fakeTrackingConsent: TrackingConsent

private var featureSdkCore: FeatureSdkCore? = null
private var sdkCore: SdkCore? = null
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note

Nit pick, as per our guidelines it should be named testedSdkCore

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

will change it in my next PR

@mariusc83 mariusc83 merged commit 7257d4d into develop Aug 2, 2024
22 checks passed
@mariusc83 mariusc83 deleted the mconstantin/rum-5525/add-integration-tests-for-sdkcore branch August 2, 2024 14:57

private lateinit var fakeTrackingConsent: TrackingConsent

private var featureSdkCore: FeatureSdkCore? = null
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

better to use lateinit var with non-nullable type. Will remove a lot of .? in the code.

keepStartingWith("org.json")
androidTestImplementation(project(":reliability:stub-feature"))
androidTestImplementation(libs.assertJ)
androidTestImplementation(libs.mockitoAndroid)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I cannot see any usages of that. Is it really needed?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants