Skip to content

Commit

Permalink
Cherry pick commit a54c179afefe38966a651902017d51918b728cf9,replace t…
Browse files Browse the repository at this point in the history
…hrowing exception with ignoring events for LibraryAdapter

commit_hash:942ed48d4f3c036ea0af4f6ec721eed0db43f257
  • Loading branch information
alexklints committed Oct 8, 2024
1 parent 818ff2b commit b50a3f2
Show file tree
Hide file tree
Showing 7 changed files with 103 additions and 57 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,20 @@ import io.appmetrica.analytics.impl.protobuf.backend.EventProto
class LibraryEventConstructor {

private val systemEventName = "appmetrica_system_event_42"
private val nullPlaceholder = "null"

fun constructEvent(
sender: String,
event: String,
payload: String
sender: String?,
event: String?,
payload: String?
): ModuleEvent {
return ModuleEvent.newBuilder(EventProto.ReportMessage.Session.Event.EVENT_CLIENT)
.withName(systemEventName)
.withAttributes(
mapOf(
"sender" to sender,
"event" to event,
"payload" to payload,
"sender" to (sender ?: nullPlaceholder),
"event" to (event ?: nullPlaceholder),
"payload" to (payload ?: nullPlaceholder),
)
)
.build()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import io.appmetrica.analytics.impl.events.LibraryEventConstructor
import io.appmetrica.analytics.impl.proxy.synchronous.LibraryAdapterSynchronousStageExecutor
import io.appmetrica.analytics.impl.proxy.validation.LibraryAdapterBarrier
import io.appmetrica.analytics.logger.appmetrica.internal.DebugLogger
import io.appmetrica.analytics.logger.appmetrica.internal.ImportantLogger
import io.appmetrica.analytics.logger.appmetrica.internal.PublicLogger

class AppMetricaLibraryAdapterProxy {

Expand All @@ -22,24 +24,31 @@ class AppMetricaLibraryAdapterProxy {
ClientServiceLocator.getInstance().clientExecutorProvider.defaultExecutor

fun activate(context: Context) {
DebugLogger.info(tag, "Activate")
barrier.activate(context)
val applicationContext = context.applicationContext
synchronousStageExecutor.activate(applicationContext)
executor.execute {
DebugLogger.info(tag, "Activate full")
provider.getInitializedImpl(applicationContext).activateFull()
if (barrier.activate(context)) {
DebugLogger.info(tag, "Activate")
val applicationContext = context.applicationContext
synchronousStageExecutor.activate(applicationContext)
executor.execute {
provider.getInitializedImpl(applicationContext).activateFull()
}
provider.markActivated()
} else {
ImportantLogger.info(tag, "Activation failed due to context is null")
}
provider.markActivated()
}

fun reportEvent(
sender: String,
event: String,
payload: String
sender: String?,
event: String?,
payload: String?
) {
barrier.reportEvent(sender, event, payload)
synchronousStageExecutor.reportEvent(sender, event, payload)
ModulesFacade.reportEvent(libraryEventConstructor.constructEvent(sender, event, payload))
if (barrier.reportEvent(sender, event, payload)) {
synchronousStageExecutor.reportEvent(sender, event, payload)
ModulesFacade.reportEvent(libraryEventConstructor.constructEvent(sender, event, payload))
} else {
val message = "Failed report event from sender: $sender with name = $event and payload = $payload"
PublicLogger.getAnonymousInstance().warning("$tag$message")
DebugLogger.warning(tag, message)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ class LibraryAdapterSynchronousStageExecutor(
}

fun reportEvent(
sender: String,
event: String,
payload: String
sender: String?,
event: String?,
payload: String?
) {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,38 +3,27 @@ package io.appmetrica.analytics.impl.proxy.validation
import android.content.Context
import io.appmetrica.analytics.impl.proxy.AppMetricaFacadeProvider
import io.appmetrica.analytics.impl.utils.validation.NonNullValidator
import io.appmetrica.analytics.impl.utils.validation.ThrowIfFailedValidator

class LibraryAdapterBarrier(
provider: AppMetricaFacadeProvider,
) {

private val contextValidator = ThrowIfFailedValidator(
NonNullValidator<Context>("Context")
)
private val activationValidator = ActivationValidator(provider)
private val senderValidator = ThrowIfFailedValidator(
NonNullValidator<String>("Sender")
)
private val eventValidator = ThrowIfFailedValidator(
NonNullValidator<String>("Event")
)
private val payloadValidator = ThrowIfFailedValidator(
NonNullValidator<String>("Payload")
)
private val contextValidator = NonNullValidator<Context>("Context")
private val activationValidator = SilentActivationValidator(provider)
private val senderValidator = NonNullValidator<String>("Sender")
private val eventValidator = NonNullValidator<String>("Event")
private val payloadValidator = NonNullValidator<String>("Payload")

fun activate(context: Context?) {
contextValidator.validate(context)
}
fun activate(context: Context?): Boolean = contextValidator.validate(context).isValid

fun reportEvent(
sender: String?,
event: String?,
payload: String?
) {
activationValidator.validate()
senderValidator.validate(sender)
eventValidator.validate(event)
payloadValidator.validate(payload)
): Boolean {
return activationValidator.validate().isValid &&
senderValidator.validate(sender).isValid &&
eventValidator.validate(event).isValid &&
payloadValidator.validate(payload).isValid
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,26 @@ class LibraryEventConstructorTest : CommonTest() {
}
.checkAll()
}

@Test
fun `constructEvent for null values`() {
val moduleEvent = constructor.constructEvent(null, null, null)

ObjectPropertyAssertions(moduleEvent)
.withPrivateFields(true)
.checkField("type", EventProto.ReportMessage.Session.Event.EVENT_CLIENT)
.checkField("name", "appmetrica_system_event_42")
.checkFieldIsNull("value")
.checkField("serviceDataReporterType", 1)
.checkFieldIsNull("environment")
.checkFieldIsNull("extras")
.checkFieldRecursively<List<Map.Entry<String, Any>>>("attributes") {
assertThat(it.actual).containsExactlyInAnyOrderElementsOf(mapOf(
"sender" to "null",
"event" to "null",
"payload" to "null",
).entries.toList())
}
.checkAll()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,14 @@ import io.appmetrica.analytics.testutils.staticRule
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.mockito.MockedStatic
import org.mockito.kotlin.any
import org.mockito.kotlin.argumentCaptor
import org.mockito.kotlin.doReturn
import org.mockito.kotlin.mock
import org.mockito.kotlin.never
import org.mockito.kotlin.verify
import org.mockito.kotlin.verifyNoInteractions
import org.mockito.kotlin.whenever

class AppMetricaLibraryAdapterProxyTest : CommonTest() {
Expand Down Expand Up @@ -64,6 +68,8 @@ class AppMetricaLibraryAdapterProxyTest : CommonTest() {
proxy = AppMetricaLibraryAdapterProxy()

barrier = barrierRule.constructionMock.constructed().first()
whenever(barrier.activate(any())).thenReturn(true)
whenever(barrier.reportEvent(any(), any(), any())).thenReturn(true)
synchronousStageExecutor =
synchronousStageExecutorRule.constructionMock.constructed().first()
libraryEventConstructor =
Expand All @@ -82,6 +88,13 @@ class AppMetricaLibraryAdapterProxyTest : CommonTest() {
verify(facade).activateFull()
}

@Test
fun `activate if not valid`() {
whenever(barrier.activate(context)).thenReturn(false)
proxy.activate(context)
verifyNoInteractions(synchronousStageExecutor, executor)
}

@Test
fun reportEvent() {
val sender = "sender_value"
Expand All @@ -99,4 +112,16 @@ class AppMetricaLibraryAdapterProxyTest : CommonTest() {
ModulesFacade.reportEvent(moduleEvent)
}
}

@Test
fun `reportEvent if not valid`() {
val sender = "sender_value"
val event = "event_value"
val payload = "payload_value"

whenever(barrier.reportEvent(sender, event, payload)).thenReturn(false)
proxy.reportEvent(sender, event, payload)
verifyNoInteractions(synchronousStageExecutor)
modulesFacadeRule.staticMock.verify({ ModulesFacade.reportEvent(any()) }, never())
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import android.content.Context
import io.appmetrica.analytics.ValidationException
import io.appmetrica.analytics.impl.proxy.AppMetricaFacadeProvider
import io.appmetrica.analytics.testutils.CommonTest
import org.assertj.core.api.Assertions.assertThat
import org.junit.Before
import org.junit.Test
import org.mockito.kotlin.mock
Expand All @@ -24,37 +25,36 @@ class LibraryAdapterBarrierTest : CommonTest() {

@Test
fun activate() {
barrier.activate(context)
assertThat(barrier.activate(context)).isTrue()
}

@Test(expected = ValidationException::class)
@Test
fun `activate for null context`() {
barrier.activate(null)
assertThat(barrier.activate(null)).isFalse()
}

@Test
fun reportEvent() {
barrier.reportEvent("sender", "event", "payload")
assertThat(barrier.reportEvent("sender", "event", "payload")).isTrue()
}

@Test(expected = ValidationException::class)
@Test
fun `reportEvent for null sender`() {
barrier.reportEvent(null, "event", "payload")
assertThat(barrier.reportEvent(null, "event", "payload")).isFalse()
}

@Test(expected = ValidationException::class)
@Test
fun `reportEvent for null event`() {
barrier.reportEvent("sender", null, "payload")
assertThat(barrier.reportEvent("sender", null, "payload")).isFalse()
}

@Test(expected = ValidationException::class)
fun `reportEvent for null payload`() {
barrier.reportEvent("sender", "event", null)
assertThat(barrier.reportEvent("sender", "event", null)).isFalse()
}

@Test(expected = ValidationException::class)
@Test
fun `reportEvent if not activated`() {
whenever(appMetricaFacadeProvider.isActivated).thenReturn(false)
barrier.reportEvent("sender", "event", "payload")
assertThat(barrier.reportEvent("sender", "event", "payload")).isFalse()
}
}

0 comments on commit b50a3f2

Please sign in to comment.