Skip to content

Commit

Permalink
Add API to decorate link with user/session info (close #639)
Browse files Browse the repository at this point in the history
  • Loading branch information
greg-el committed Sep 8, 2023
1 parent 9d541a5 commit 38b379e
Show file tree
Hide file tree
Showing 4 changed files with 295 additions and 25 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
package com.snowplowanalytics.snowplow.tracker


import android.net.Uri
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.platform.app.InstrumentationRegistry
import com.snowplowanalytics.core.tracker.CrossDeviceParameter
import com.snowplowanalytics.snowplow.Snowplow
import com.snowplowanalytics.snowplow.configuration.NetworkConfiguration
import com.snowplowanalytics.snowplow.configuration.SessionConfiguration
import com.snowplowanalytics.snowplow.configuration.SubjectConfiguration
import com.snowplowanalytics.snowplow.configuration.TrackerConfiguration
import com.snowplowanalytics.snowplow.controller.SessionController
import com.snowplowanalytics.snowplow.controller.TrackerController
import com.snowplowanalytics.snowplow.event.ScreenView
import com.snowplowanalytics.snowplow.network.HttpMethod
import com.snowplowanalytics.snowplow.util.TimeMeasure
import org.junit.Assert
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import java.util.concurrent.TimeUnit


@RunWith(AndroidJUnit4::class)
class LinkDecoratorTest {
private lateinit var tracker: TrackerController
private lateinit var session: SessionController
private lateinit var userId: String
private val testLink = Uri.parse("http://example.com")
private fun matchesRegex(pattern: Regex, result: Uri) {
Assert.assertTrue(
"$result\ndoes not match expected: $pattern",
pattern.matches(result.toString())
)
}


@Before
fun before() {
tracker = getTracker()
session = tracker.session!!
userId = session.userId
}

@Test
fun testWithoutSession() {
val tracker = getTrackerNoSession()
val result = tracker.decorateLink(testLink)
Assert.assertEquals(null, result)
}

@Test
fun testDecorateUriWithNoParams() {
tracker.track(ScreenView("test"))

val pattern =
Regex("""http://example\.com\?_sp=$userId\.\d{13}\.${session.sessionId}\.decoratorTest\.mob\.subjectUserId""")
val result = tracker.decorateLink(testLink)

matchesRegex(pattern, result!!)
}

@Test
fun testDecorateUriWithExistingSpParam() {
tracker.track(ScreenView("test"))

val pattern =
Regex("""http://example\.com\?_sp=$userId\.\d{13}\.${session.sessionId}\.decoratorTest\.mob\.subjectUserId""")
val result = tracker.decorateLink(testLink.buildUpon().appendQueryParameter("_sp", "test").build())

matchesRegex(pattern, result!!)
}

@Test
fun testDecorateUriWithOtherParam() {
tracker.track(ScreenView("test"))

val pattern =
Regex("""http://example\.com\?a=b&_sp=$userId\.\d{13}\.${session.sessionId}\.decoratorTest\.mob\.subjectUserId""")
val result =
tracker.decorateLink(testLink.buildUpon().appendQueryParameter("a", "b").build())

matchesRegex(pattern, result!!)
}

@Test
fun testDecorateUriWithParameters() {
tracker.track(ScreenView("test"))

val sessionId = session.sessionId
val expectedParams = hashMapOf(
listOf(CrossDeviceParameter.SESSION_ID) to ".$sessionId",

listOf(
CrossDeviceParameter.SESSION_ID,
CrossDeviceParameter.SOURCE_ID
) to ".$sessionId.decoratorTest",

listOf(
CrossDeviceParameter.SESSION_ID,
CrossDeviceParameter.SOURCE_ID,
CrossDeviceParameter.SOURCE_PLATFORM
) to ".$sessionId.decoratorTest.mob",

listOf(
CrossDeviceParameter.SESSION_ID,
CrossDeviceParameter.SOURCE_ID,
CrossDeviceParameter.SOURCE_PLATFORM,
CrossDeviceParameter.USER_ID
) to ".$sessionId.decoratorTest.mob.subjectUserId",

listOf(
CrossDeviceParameter.SESSION_ID,
CrossDeviceParameter.SOURCE_PLATFORM,
) to ".$sessionId..mob",

listOf(
CrossDeviceParameter.SOURCE_ID,
CrossDeviceParameter.USER_ID
) to "..decoratorTest..subjectUserId",

listOf(
CrossDeviceParameter.USER_ID
) to "....subjectUserId",

emptyList<CrossDeviceParameter>() to "",
)

for ((param, spVal) in expectedParams.entries) {
val pattern =
Regex("""http://example\.com\?_sp=$userId\.\d{13}$spVal""")
val result = tracker.decorateLink(testLink, param)

matchesRegex(pattern, result!!)
}
}

fun getTracker(): TrackerController {
val context = InstrumentationRegistry.getInstrumentation().targetContext
// Setup tracker
val networkConfiguration = NetworkConfiguration("fake-url", HttpMethod.POST)

val trackerConfiguration = TrackerConfiguration("decoratorTest")
.sessionContext(true)

val subjectConfig = SubjectConfiguration().userId("subjectUserId")

val sessionConfiguration = SessionConfiguration(
TimeMeasure(6, TimeUnit.SECONDS),
TimeMeasure(30, TimeUnit.SECONDS),
)

return Snowplow.createTracker(
context,
"namespace" + Math.random(),
networkConfiguration,
trackerConfiguration,
sessionConfiguration,
subjectConfig
)
}

fun getTrackerNoSession(): TrackerController {
val context = InstrumentationRegistry.getInstrumentation().targetContext
// Setup tracker
val networkConfiguration = NetworkConfiguration("fake-url", HttpMethod.POST)

val trackerConfiguration = TrackerConfiguration("decoratorTest")
.sessionContext(false)


return Snowplow.createTracker(
context,
"namespace" + Math.random(),
networkConfiguration,
trackerConfiguration,
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package com.snowplowanalytics.core.tracker

import com.snowplowanalytics.snowplow.controller.SessionController
import com.snowplowanalytics.snowplow.controller.TrackerController

/**
* The optional parameters to include in the query string added by [TrackerController.decorateLink]
*/
enum class CrossDeviceParameter {
/**
* Value of [SessionController.sessionId]
*/
SESSION_ID,

/**
* Value of [Tracker.appId]
*/
SOURCE_ID,

/**
* Value of [Tracker.platform]
*/
SOURCE_PLATFORM,

/**
* Value of [Subject.userId]
*/
USER_ID,
}
Loading

0 comments on commit 38b379e

Please sign in to comment.