Skip to content

Commit

Permalink
add tests for capture method
Browse files Browse the repository at this point in the history
  • Loading branch information
marandaneto committed Oct 2, 2023
1 parent 2161c35 commit b73c4b3
Show file tree
Hide file tree
Showing 5 changed files with 174 additions and 17 deletions.
1 change: 1 addition & 0 deletions posthog/api/posthog.api
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
public final class com/posthog/PostHog : com/posthog/PostHogInterface {
public static final field Companion Lcom/posthog/PostHog$Companion;
public synthetic fun <init> (Ljava/util/concurrent/ExecutorService;Lkotlin/jvm/internal/DefaultConstructorMarker;)V
public fun alias (Ljava/lang/String;Ljava/util/Map;)V
public fun capture (Ljava/lang/String;Ljava/lang/String;Ljava/util/Map;Ljava/util/Map;Ljava/util/Map;Ljava/util/Map;)V
public fun close ()V
Expand Down
82 changes: 68 additions & 14 deletions posthog/src/main/java/com/posthog/PostHog.kt
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,16 @@ import com.posthog.internal.PostHogMemoryPreferences
import com.posthog.internal.PostHogQueue
import com.posthog.internal.PostHogSendCachedEventsIntegration
import com.posthog.internal.PostHogSerializer
import com.posthog.internal.PostHogThreadFactory
import java.util.UUID

public class PostHog private constructor() : PostHogInterface {
import java.util.concurrent.ExecutorService
import java.util.concurrent.Executors

public class PostHog private constructor(
private val queueExecutor: ExecutorService = Executors.newSingleThreadScheduledExecutor(
PostHogThreadFactory("PostHogQueueThread"),
),
) : PostHogInterface {
@Volatile
private var enabled = false

Expand All @@ -20,7 +27,6 @@ public class PostHog private constructor() : PostHogInterface {
private var config: PostHogConfig? = null

private var featureFlags: PostHogFeatureFlags? = null
private var api: PostHogApi? = null
private var queue: PostHogQueue? = null
private var memoryPreferences = PostHogMemoryPreferences()

Expand All @@ -41,19 +47,26 @@ public class PostHog private constructor() : PostHogInterface {
val serializer = PostHogSerializer(config)
val dateProvider = PostHogCalendarDateProvider()
val api = PostHogApi(config, serializer, dateProvider)
val queue = PostHogQueue(config, api, serializer, dateProvider)
val queue = PostHogQueue(config, api, serializer, dateProvider, queueExecutor)
val featureFlags = PostHogFeatureFlags(config, api)

// no need to lock optOut here since the setup is locked already
val optOut = config.cachePreferences?.getValue("opt-out", defaultValue = false) as? Boolean
val optOut = config.cachePreferences?.getValue(
"opt-out",
defaultValue = config.optOut,
) as? Boolean
optOut?.let {
config.optOut = optOut
}

val startDate = dateProvider.currentDate()
val sendCachedEventsIntegration = PostHogSendCachedEventsIntegration(config, api, serializer, startDate)
val sendCachedEventsIntegration = PostHogSendCachedEventsIntegration(
config,
api,
serializer,
startDate,
)

this.api = api
this.config = config
this.queue = queue
this.featureFlags = featureFlags
Expand Down Expand Up @@ -117,7 +130,8 @@ public class PostHog private constructor() : PostHogInterface {
try {
it.uninstall()
} catch (e: Throwable) {
config.logger.log("Integration ${it.javaClass.name} failed to uninstall: $e.")
config.logger
.log("Integration ${it.javaClass.name} failed to uninstall: $e.")
}
}
}
Expand Down Expand Up @@ -147,7 +161,10 @@ public class PostHog private constructor() : PostHogInterface {

private var distinctId: String
get() {
return config?.cachePreferences?.getValue("distinctId", defaultValue = anonymousId) as? String ?: ""
return config?.cachePreferences?.getValue(
"distinctId",
defaultValue = anonymousId,
) as? String ?: ""
}
set(value) {
config?.cachePreferences?.setValue("distinctId", value)
Expand Down Expand Up @@ -215,7 +232,6 @@ public class PostHog private constructor() : PostHogInterface {
return props
}

// test: $merge_dangerously
public override fun capture(
event: String,
distinctId: String?,
Expand All @@ -234,7 +250,17 @@ public class PostHog private constructor() : PostHogInterface {

val newDistinctId = distinctId ?: this.distinctId

val postHogEvent = PostHogEvent(event, newDistinctId, properties = buildProperties(newDistinctId, properties, userProperties, userPropertiesSetOnce, groupProperties))
val postHogEvent = PostHogEvent(
event,
newDistinctId,
properties = buildProperties(
newDistinctId,
properties,
userProperties,
userPropertiesSetOnce,
groupProperties,
),
)
queue?.add(postHogEvent)
}

Expand Down Expand Up @@ -320,7 +346,13 @@ public class PostHog private constructor() : PostHogInterface {
props.putAll(it)
}

capture("\$identify", distinctId = distinctId, properties = props, userProperties = userProperties, userPropertiesSetOnce = userPropertiesSetOnce)
capture(
"\$identify",
distinctId = distinctId,
properties = props,
userProperties = userProperties,
userPropertiesSetOnce = userPropertiesSetOnce,
)

if (previousDistinctId != distinctId) {
// We keep the AnonymousId to be used by decide calls and identify to link the previousId
Expand Down Expand Up @@ -486,6 +518,16 @@ public class PostHog private constructor() : PostHogInterface {
return instance
}

@PostHogVisibleForTesting
internal fun <T : PostHogConfig> withInternal(
config: T,
queueExecutor: ExecutorService,
): PostHogInterface {
val instance = PostHog(queueExecutor)
instance.setup(config)
return instance
}

public override fun <T : PostHogConfig> setup(config: T) {
shared.setup(config)
}
Expand All @@ -502,7 +544,14 @@ public class PostHog private constructor() : PostHogInterface {
userPropertiesSetOnce: Map<String, Any>?,
groupProperties: Map<String, Any>?,
) {
shared.capture(event, distinctId = distinctId, properties = properties, userProperties = userProperties, userPropertiesSetOnce = userPropertiesSetOnce, groupProperties = groupProperties)
shared.capture(
event,
distinctId = distinctId,
properties = properties,
userProperties = userProperties,
userPropertiesSetOnce = userPropertiesSetOnce,
groupProperties = groupProperties,
)
}

public override fun identify(
Expand All @@ -511,7 +560,12 @@ public class PostHog private constructor() : PostHogInterface {
userProperties: Map<String, Any>?,
userPropertiesSetOnce: Map<String, Any>?,
) {
shared.identify(distinctId, properties = properties, userProperties = userProperties, userPropertiesSetOnce = userPropertiesSetOnce)
shared.identify(
distinctId,
properties = properties,
userProperties = userProperties,
userPropertiesSetOnce = userPropertiesSetOnce,
)
}

public override fun reloadFeatureFlags(onFeatureFlags: PostHogOnFeatureFlags?) {
Expand Down
3 changes: 1 addition & 2 deletions posthog/src/main/java/com/posthog/internal/PostHogQueue.kt
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import java.util.Timer
import java.util.TimerTask
import java.util.UUID
import java.util.concurrent.ExecutorService
import java.util.concurrent.Executors
import java.util.concurrent.atomic.AtomicBoolean
import kotlin.concurrent.schedule
import kotlin.math.min
Expand All @@ -28,7 +27,7 @@ internal class PostHogQueue(
private val api: PostHogApi,
private val serializer: PostHogSerializer,
private val dateProvider: PostHogDateProvider,
private val executor: ExecutorService = Executors.newSingleThreadScheduledExecutor(PostHogThreadFactory("PostHogQueueThread")),
private val executor: ExecutorService,
) {

private val deque: ArrayDeque<File> = ArrayDeque()
Expand Down
93 changes: 92 additions & 1 deletion posthog/src/test/java/com/posthog/PostHogTest.kt
Original file line number Diff line number Diff line change
@@ -1,9 +1,100 @@
package com.posthog

import com.posthog.internal.PostHogBatchEvent
import com.posthog.internal.PostHogSerializer
import com.posthog.internal.PostHogThreadFactory
import org.junit.Rule
import org.junit.rules.TemporaryFolder
import java.util.concurrent.Executors
import kotlin.test.AfterTest
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertFalse
import kotlin.test.assertNotNull
import kotlin.test.assertTrue

internal class PostHogTest {

@get:Rule
val tmpDir = TemporaryFolder()

private val queueExecutor = Executors.newSingleThreadScheduledExecutor(PostHogThreadFactory("queueExecutor"))
private val serializer = PostHogSerializer(PostHogConfig(apiKey))

fun getSut(
host: String = "",
storagePrefix: String = tmpDir.newFolder().absolutePath,
optOut: Boolean = false,
preloadFeatureFlags: Boolean = true,
): PostHogInterface {
val config = PostHogConfig(apiKey, host).apply {
// for testing
flushAt = 1
this.storagePrefix = storagePrefix
this.optOut = optOut
this.preloadFeatureFlags = preloadFeatureFlags
}
return PostHog.withInternal(config, queueExecutor)
}

@AfterTest
fun `set down`() {
tmpDir.root.deleteRecursively()
}

@Test
fun `optOut is disabled by default`() {
val sut = getSut()

assertFalse(sut.isOptOut())

sut.close()
}

@Test
fun `deserializes json to date`() {
fun `optOut is enabled if given`() {
val sut = getSut(optOut = true)

assertTrue(sut.isOptOut())

sut.close()
}

@Test
fun `captures an event`() {
val http = mockHttp()
val url = http.url("/")

val sut = getSut(url.toString(), preloadFeatureFlags = false)

sut.capture(
event,
distinctId,
props,
userProperties = userProps,
userPropertiesSetOnce = userPropsOnce,
groupProperties = groupProps,
)

queueExecutor.shutdownAndAwaitTermination()

val request = http.takeRequest()

assertEquals(1, http.requestCount)
val content = request.body.unGzip()
val batch = serializer.deserialize<PostHogBatchEvent>(content.reader())

assertEquals(apiKey, batch.apiKey)
assertNotNull(batch.sentAt)

val theEvent = batch.batch.first()
assertEquals(event, theEvent.event)
assertEquals(distinctId, theEvent.distinctId)
assertNotNull(theEvent.timestamp)
assertNotNull(theEvent.uuid)
assertEquals("value", theEvent.properties!!["prop"] as String)
assertEquals(userProps, theEvent.properties!!["\$set"])
assertEquals(userPropsOnce, theEvent.properties!!["\$set_once"])
assertEquals(groupProps, theEvent.properties!!["\$groups"])
}
}
12 changes: 12 additions & 0 deletions posthog/src/test/java/com/posthog/Utils.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ package com.posthog
import com.google.gson.internal.bind.util.ISO8601Utils
import okhttp3.mockwebserver.MockResponse
import okhttp3.mockwebserver.MockWebServer
import okio.Buffer
import okio.GzipSource
import okio.buffer
import java.lang.RuntimeException
import java.text.ParsePosition
import java.util.Date
Expand Down Expand Up @@ -40,6 +43,9 @@ public const val event: String = "event"
public const val distinctId: String = "distinctId"
public const val anonId: String = "anonId"
public val groups: Map<String, Any> = mapOf("group1" to "theValue")
public val userProps: Map<String, Any> = mapOf("user1" to "theValue")
public val userPropsOnce: Map<String, Any> = mapOf("logged" to true)
public val groupProps: Map<String, Any> = mapOf("premium" to true)
public val props: Map<String, Any> = mapOf<String, Any>("prop" to "value")
public val uuid: UUID = UUID.fromString("8c04e5c1-8f6e-4002-96fd-1804799b6ffe")

Expand Down Expand Up @@ -99,3 +105,9 @@ public fun mockHttp(
}
return mock
}

public fun Buffer.unGzip(): String {
return GzipSource(this).use { source ->
source.buffer().use { bufferedSource -> bufferedSource.readUtf8() }
}
}

0 comments on commit b73c4b3

Please sign in to comment.