Skip to content

Added missing Firebase Performance SDK implementation for Android and iOS #726

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

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
package dev.gitlive.firebase.perf.metrics

import com.google.firebase.perf.v1.NetworkRequestMetric
import dev.gitlive.firebase.Firebase
import dev.gitlive.firebase.FirebaseOptions
import dev.gitlive.firebase.apps
import dev.gitlive.firebase.initialize
import dev.gitlive.firebase.perf.FirebasePerformance
import dev.gitlive.firebase.perf.context
import dev.gitlive.firebase.perf.performance
import dev.gitlive.firebase.runBlockingTest
import kotlinx.coroutines.delay
import kotlinx.coroutines.test.runTest
import kotlin.test.AfterTest
import kotlin.test.BeforeTest
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.time.Duration.Companion.seconds

class AndroidHttpMetricTest {

private lateinit var performance: FirebasePerformance

companion object {
const val URL = "https://example.com"
val httpMethod = NetworkRequestMetric.HttpMethod.POST.name
}

@BeforeTest
fun initializeFirebase() {
val app = Firebase.apps(context).firstOrNull() ?: Firebase.initialize(
context,
FirebaseOptions(
applicationId = "1:846484016111:ios:dd1f6688bad7af768c841a",
apiKey = "AIzaSyCK87dcMFhzCz_kJVs2cT2AVlqOTLuyWV0",
databaseUrl = "https://fir-kotlin-sdk.firebaseio.com",
storageBucket = "fir-kotlin-sdk.appspot.com",
projectId = "fir-kotlin-sdk",
gcmSenderId = "846484016111",
),
)

performance = Firebase.performance(app)
}

@AfterTest
fun deinitializeFirebase() = runBlockingTest {
// Performance runs installation in the background, which crashes if the app is deleted before completion
delay(5.seconds)
Firebase.apps(context).forEach {
it.delete()
}
}

@Test
fun testGetAttributes() = runTest {
val trace = performance.newHttpMetric(URL, httpMethod)
trace.start()
val values = listOf(1, 2, 3)

values.forEach {
trace.putAttribute("Test_Get_Attributes_$it", "Test Get Attributes Value $it")
}

val attributes = trace.getAttributes()

assertEquals(3, attributes.size)

// TODO: refactor? this should check if keys are same as you have placed and if values are same as you have placed
attributes.onEachIndexed { _, entry ->
assertEquals(entry.key.last(), entry.value.last())
}

trace.stop()
}

@Test
fun testGetAttribute() = runTest {
val trace = performance.newHttpMetric(URL, httpMethod)
trace.start()
trace.putAttribute("Test_Get_Attribute", "Test Get Attribute Value")

assertEquals("Test Get Attribute Value", trace.getAttribute("Test_Get_Attribute"))
trace.stop()
}

@Test
fun testPutAttribute() = runTest {
val trace = performance.newHttpMetric(URL, httpMethod)
trace.start()
trace.putAttribute("Test_Put_Attribute", "Test Put Attribute Value")

assertEquals("Test Put Attribute Value", trace.getAttribute("Test_Put_Attribute"))
trace.stop()
}

@Test
fun testRemoveAttribute() = runTest {
val trace = performance.newHttpMetric(URL, httpMethod)
trace.start()

trace.putAttribute("Test_Put_Attribute", "Test Put Attribute Value")
assertEquals("Test Put Attribute Value", trace.getAttribute("Test_Put_Attribute"))

trace.removeAttribute("Test_Put_Attribute")
assertEquals(null, trace.getAttribute("Test_Put_Attribute"))

trace.stop()
}

@Test
fun testSettingHttpMetrics() = runTest {
val trace = performance.newHttpMetric(URL, httpMethod)
trace.start()

trace.setHttpResponseCode(1)
trace.setRequestPayloadSize(10L)
trace.setResponseContentType("application/json")
trace.setResponsePayloadSize(44L)

trace.stop()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,8 @@ class AndroidTraceTest {

assertEquals(3, attributes.size)

// TODO: refactor? this should check if keys are same as you have placed and if values are same as you have placed
attributes.onEachIndexed { _, entry ->

assertEquals(entry.key.last(), entry.value.last())
}

Expand All @@ -87,4 +87,30 @@ class AndroidTraceTest {
assertEquals("Test Put Attribute Value", trace.getAttribute("Test_Put_Attribute"))
trace.stop()
}

@Test
fun testLongMetric() = runTest {
val trace = performance.newTrace("testLongMetric")
trace.start()

trace.putMetric("Test_Put_Attribute", 3L)
trace.incrementMetric("Test_Put_Attribute", 1L)

assertEquals(4L, trace.getLongMetric("Test_Put_Attribute"))
trace.stop()
}

@Test
fun testRemoveAttribute() = runTest {
val trace = performance.newTrace("testRemoveAttribute")
trace.start()

trace.putAttribute("Test_Put_Attribute", "Test Put Attribute Value")
assertEquals("Test Put Attribute Value", trace.getAttribute("Test_Put_Attribute"))

trace.removeAttribute("Test_Put_Attribute")
assertEquals(null, trace.getAttribute("Test_Put_Attribute"))

trace.stop()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package dev.gitlive.firebase.perf.metrics

import com.google.firebase.perf.metrics.HttpMetric as AndroidHttpMetric

public val HttpMetric.android: AndroidHttpMetric get() = android

public actual class HttpMetric(internal val android: AndroidHttpMetric) {
public actual fun getAttribute(attribute: String): String? = android.getAttribute(attribute)

public actual fun getAttributes(): Map<String, String> = android.attributes

public actual fun putAttribute(attribute: String, value: String) {
android.putAttribute(attribute, value)
}

public actual fun removeAttribute(attribute: String) {
android.removeAttribute(attribute)
}

public actual fun setHttpResponseCode(responseCode: Int) {
android.setHttpResponseCode(responseCode)
}

public actual fun setRequestPayloadSize(bytes: Long) {
android.setRequestPayloadSize(bytes)
}

public actual fun setResponseContentType(contentType: String) {
android.setResponseContentType(contentType)
}

public actual fun setResponsePayloadSize(bytes: Long) {
android.setRequestPayloadSize(bytes)
}

public actual fun start() {
android.start()
}

public actual fun stop() {
android.stop()
}

// TODO: android.markRequestComplete()
// TODO: android.markRequestStart()
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package dev.gitlive.firebase.perf.metrics

import com.google.firebase.perf.metrics.Trace as AndroidTrace
import dev.gitlive.firebase.perf.session.PerfSession
import com.google.firebase.perf.metrics.Trace as AndroidTrace

public val Trace.android: AndroidTrace get() = android

Expand All @@ -25,15 +25,15 @@ public actual class Trace internal constructor(internal val android: AndroidTrac
android.putMetric(metricName, value)
}

public fun getAttributes(): Map<String, String> = android.attributes
public actual fun getAttributes(): Map<String, String> = android.attributes

public fun getAttribute(attribute: String): String? = android.getAttribute(attribute)
public actual fun getAttribute(attribute: String): String? = android.getAttribute(attribute)

public fun putAttribute(attribute: String, value: String) {
public actual fun putAttribute(attribute: String, value: String) {
android.putAttribute(attribute, value)
}

public fun removeAttribute(attribute: String) {
public actual fun removeAttribute(attribute: String) {
android.removeAttribute(attribute)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,29 @@ package dev.gitlive.firebase.perf

import dev.gitlive.firebase.Firebase
import dev.gitlive.firebase.FirebaseApp
import dev.gitlive.firebase.android as publicAndroid
import dev.gitlive.firebase.perf.metrics.HttpMetric
import dev.gitlive.firebase.perf.metrics.Trace
import dev.gitlive.firebase.android as publicAndroid

public val FirebasePerformance.android: com.google.firebase.perf.FirebasePerformance get() = com.google.firebase.perf.FirebasePerformance.getInstance()

public actual val Firebase.performance: FirebasePerformance get() =
FirebasePerformance(com.google.firebase.perf.FirebasePerformance.getInstance())
public actual val Firebase.performance: FirebasePerformance
get() =
FirebasePerformance(com.google.firebase.perf.FirebasePerformance.getInstance())

public actual fun Firebase.performance(app: FirebaseApp): FirebasePerformance =
FirebasePerformance(app.publicAndroid.get(com.google.firebase.perf.FirebasePerformance::class.java))

public actual class FirebasePerformance(internal val android: com.google.firebase.perf.FirebasePerformance) {
public actual fun isPerformanceCollectionEnabled(): Boolean = android.isPerformanceCollectionEnabled

public actual fun newTrace(traceName: String): Trace = Trace(android.newTrace(traceName))

public actual fun isPerformanceCollectionEnabled(): Boolean = android.isPerformanceCollectionEnabled

public actual fun setPerformanceCollectionEnabled(enable: Boolean) {
android.isPerformanceCollectionEnabled = enable
}

public actual fun newHttpMetric(url: String, httpMethod: String): HttpMetric = HttpMetric(android.newHttpMetric(url, httpMethod))
}

public actual open class FirebasePerformanceException(message: String) : com.google.firebase.FirebaseException(message)
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package dev.gitlive.firebase.perf.metrics

public expect class HttpMetric {
public fun getAttribute(attribute: String): String?
public fun getAttributes(): Map<String, String>
public fun putAttribute(attribute: String, value: String)
public fun removeAttribute(attribute: String)
public fun setHttpResponseCode(responseCode: Int)
public fun setRequestPayloadSize(bytes: Long)
public fun setResponseContentType(contentType: String)
public fun setResponsePayloadSize(bytes: Long)
public fun start()
public fun stop()
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,9 @@ package dev.gitlive.firebase.perf.metrics

/** Trace allows you to set beginning and end of a certain action in your app. */
public expect class Trace {
/** Starts this trace. */
public fun start()
public fun getAttribute(attribute: String): String?

/** Stops this trace. */
public fun stop()
public fun getAttributes(): Map<String, String>

/**
* Gets the value of the metric with the given name in the current trace. If a metric with the
Expand All @@ -29,6 +27,8 @@ public expect class Trace {
*/
public fun incrementMetric(metricName: String, incrementBy: Long)

public fun putAttribute(attribute: String, value: String)

/**
* Sets the value of the metric with the given name in this trace to the value provided. If a
* metric with the given name doesn't exist, a new one will be created. If the trace has not been
Expand All @@ -40,4 +40,12 @@ public expect class Trace {
* @param value The value to which the metric should be set to.
*/
public fun putMetric(metricName: String, value: Long)

public fun removeAttribute(attribute: String)

/** Starts this trace. */
public fun start()

/** Stops this trace. */
public fun stop()
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package dev.gitlive.firebase.perf
import dev.gitlive.firebase.Firebase
import dev.gitlive.firebase.FirebaseApp
import dev.gitlive.firebase.FirebaseException
import dev.gitlive.firebase.perf.metrics.HttpMetric
import dev.gitlive.firebase.perf.metrics.Trace

/** Returns the [FirebasePerformance] instance of the default [FirebaseApp]. */
Expand All @@ -20,14 +21,6 @@ public expect fun Firebase.performance(app: FirebaseApp): FirebasePerformance
* to the Firebase backend. To stop sending performance events, call [setPerformanceCollectionEnabled] with value [false].
*/
public expect class FirebasePerformance {
/**
* Creates a Trace object with given name.
*
* @param traceName name of the trace, requires no leading or trailing whitespace, no leading
* underscore '_' character.
* @return the new Trace object.
*/
public fun newTrace(traceName: String): Trace

/**
* Determines whether performance monitoring is enabled or disabled. This respects the Firebase
Expand All @@ -40,6 +33,17 @@ public expect class FirebasePerformance {
*/
public fun isPerformanceCollectionEnabled(): Boolean

public fun newHttpMetric(url: String, httpMethod: String): HttpMetric

/**
* Creates a Trace object with given name.
*
* @param traceName name of the trace, requires no leading or trailing whitespace, no leading
* underscore '_' character.
* @return the new Trace object.
*/
public fun newTrace(traceName: String): Trace

/**
* Enables or disables performance monitoring. This setting is persisted and applied on future
* invocations of your application. By default, performance monitoring is enabled. If you need to
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,16 @@ import dev.gitlive.firebase.initialize
import dev.gitlive.firebase.runBlockingTest
import dev.gitlive.firebase.runTest
import kotlinx.coroutines.delay
import kotlin.test.*
import kotlin.test.AfterTest
import kotlin.test.BeforeTest
import kotlin.test.Test
import kotlin.test.assertFalse
import kotlin.test.assertNotNull
import kotlin.test.assertTrue
import kotlin.time.Duration.Companion.seconds

expect val context: Any

expect annotation class IgnoreForAndroidUnitTest()

@IgnoreForAndroidUnitTest
Expand Down Expand Up @@ -65,4 +71,6 @@ class FirebasePerformanceTest {

assertTrue(performance.isPerformanceCollectionEnabled())
}

// TODO: add new tests
}
Loading