Skip to content

Commit

Permalink
Merge branch 'development'
Browse files Browse the repository at this point in the history
  • Loading branch information
sofakingforever committed Aug 23, 2018
2 parents eb743b5 + 60db96a commit 807002b
Show file tree
Hide file tree
Showing 25 changed files with 402 additions and 49 deletions.
11 changes: 7 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,9 @@ repositories {
dependencies {
def version = '1.0.10'
def version = '1.0.11'
// add the basic analytics interface library
// add the basic analytics interface library - incl. LoggerDispatcher
compile "com.sofakingforever.analytics:analytics:version@aar"
// then add the kits you need
Expand All @@ -46,12 +46,15 @@ Initiate analytics and send events

```kotlin
// init analytics
analytics = Analytics(this, AnswersDispatcherImpl(), FirebaseDispatcherImpl())
analytics = Analytics(context = context,
FirebaseDispatcherImpl(init = true),
MixPanelDispatcherImpl(init = true, projectToken = "TOKEN"),
AnswersDispatcherImpl(init = true))

// send event
analytics.track(SimpleEvent())

// declare event - will be sent to both Answers and Firebase
// declare event - will be sent to both Firebase, MixPanel and Answers
class SimpleEvent : CustomEvent {
override fun getEventName(kit: AnalyticsKit): String = "Simple Event"

Expand Down
19 changes: 17 additions & 2 deletions analytics/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -37,17 +37,32 @@ android {
}
}

// testOptions {
// unitTests.returnDefaultValues = true
// }
}

dependencies {

implementation fileTree(dir: 'libs', include: ['*.jar'])

implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"

implementation 'com.android.support:appcompat-v7:28.0.0-rc01'
testImplementation 'junit:junit:4.12'


androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"

// required if you want to use Mockito for unit tests
testImplementation 'org.mockito:mockito-core:2.7.22'
// required if you want to use Mockito for Android tests
androidTestImplementation 'org.mockito:mockito-android:2.7.22'

// testCompile 'org.powermock:powermock:1.6.5'
// testCompile 'org.powermock:powermock-module-junit4:1.6.5'
//
// testCompile 'org.powermock:powermock-api-mockito:1.6.5'


}
Expand Down
26 changes: 21 additions & 5 deletions analytics/src/main/java/com/sofakingforever/analytics/Analytics.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,28 @@ package com.sofakingforever.analytics
import android.content.Context
import android.util.Log
import com.sofakingforever.analytics.events.base.Event
import com.sofakingforever.analytics.exceptions.EventNotTrackedException

/**
* The *Analytics* class is in charge of tracking any *Event* implementation.
*
* @property context any context from the app
* @param context any context from the app
* @property dispatchers list of *AnalyticsDispatchers* to trigger for every event
*
* @constructor create an instance of the *Analytics* class
*/
class Analytics(context: Context, private vararg val dispatchers: AnalyticsDispatcher) {


private val enabledKitMap: EnabledMap<AnalyticsKit> = EnabledMap()
private val enabledDispatcherMap: EnabledMap<String> = EnabledMap()

val settings: AnalyticsSettings = AnalyticsSettings()

init {
dispatchers.forEach { dispatcher ->
if (dispatcher.init) {
dispatcher.initDispatcher(context)
dispatcher.initDispatcher(context.applicationContext)
}
}
}
Expand All @@ -32,20 +37,31 @@ class Analytics(context: Context, private vararg val dispatchers: AnalyticsDispa
if (settings.isAnalyticsEnabled.not()) return

events.forEach {

dispatchers.forEach { dispatcher ->

if (enabledKitMap.isDisabled(dispatcher.kit)) {
return
}
if (enabledDispatcherMap.isDisabled(dispatcher.dispatcherName)) {
return
}
try {
dispatcher.track(it)
} catch (e: Exception) {
Log.e("Analytics", "${dispatcher.kit.name} dispatcher couldn't fire \"${it.javaClass.name}\" event", e)
settings.exceptionHandler?.onException(e)
settings.exceptionHandler?.onException(EventNotTrackedException(dispatcher, it, e))
}
}


}
}

fun setKitEnabled(kit: AnalyticsKit, enabled: Boolean) {
enabledKitMap[kit] = enabled
}

fun setDispatcherEnabled(dispatcherName: String, enabled: Boolean) {
enabledDispatcherMap[dispatcherName] = enabled
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ interface AnalyticsDispatcher {

val kit: AnalyticsKit

val dispatcherName : String
/**
* Should call the analytics library's initiation methods
*/
Expand All @@ -33,7 +34,7 @@ interface AnalyticsDispatcher {

fun trackInviteEvent(inviteEvent: InviteEvent)

fun setUserProperty(property : SetUserProperty)
fun setUserProperty(property: SetUserProperty)

/**
* This method is called from the parent @Analytics class for each event.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.sofakingforever.analytics

class EnabledMap<Key> : LinkedHashMap<Key, Boolean>() {

fun isDisabled(something : Key) : Boolean = this[something] == false

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.sofakingforever.analytics.exceptions

import com.sofakingforever.analytics.AnalyticsDispatcher
import com.sofakingforever.analytics.events.base.Event

class EventNotTrackedException(message: String?, cause: Throwable?) : RuntimeException(message, cause) {

constructor(dispatcher: AnalyticsDispatcher, event: Event, t: Throwable) : this("${dispatcher.dispatcherName} dispatcher couldn't fire \"${event.javaClass.name}\" event", t)

}
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,12 @@ import com.sofakingforever.analytics.events.SetUserProperty
*/
class LoggerDispatcherImpl(override val init: Boolean) : AnalyticsDispatcher {


override val dispatcherName: String = "LoggerDispatcher"

constructor() : this(true)

private val tag = "LoggerDispatcher"

private val tag = dispatcherName

override val kit: AnalyticsKit = LoggerKit.instance

Expand All @@ -40,7 +41,8 @@ class LoggerDispatcherImpl(override val init: Boolean) : AnalyticsDispatcher {
override fun trackInviteEvent(inviteEvent: InviteEvent) {
Log.d(tag, "Tracking inviteEvent ${inviteEvent.packageName}")
}

override fun setUserProperty(property: SetUserProperty) {
// used only for certain analytics
Log.d(tag, "Tracking user property ${property.key} = ${property.value}")
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
package com.sofakingforever.library

import android.content.Context
import android.util.Log
import com.sofakingforever.analytics.Analytics
import com.sofakingforever.analytics.AnalyticsSettings
import com.sofakingforever.analytics.exceptions.EventNotTrackedException
import com.sofakingforever.analytics.exceptions.UnsupportedEventException
import com.sofakingforever.library.dispatcher.TestKit
import com.sofakingforever.library.dispatcher.TestableDispatcher
import com.sofakingforever.library.events.InitDispatcherEvent
import com.sofakingforever.library.events.TestContentViewEvent
import com.sofakingforever.library.events.TestCustomEvent
import com.sofakingforever.library.events.UnsupportedEvent
import org.junit.Test
import org.mockito.Mockito
import org.mockito.Mockito.mock

class AnalyticsUnitTest {

private val contextMock = mock(Context::class.java)

private lateinit var analytics: Analytics

private val dispatcher = TestableDispatcher()
private var raisedException: Exception? = null

init {
Mockito.`when`(contextMock.applicationContext).thenReturn(contextMock)
}

@Test
fun testAnalytics() {

analytics = Analytics(contextMock, dispatcher).apply {

this.settings.exceptionHandler = object : AnalyticsSettings.ExceptionHandler {
override fun onException(e: Exception) {
raisedException = e
}

}
}

// track some events
trackTestEvents()

// assert events
assertEvents()

// assert no exceptions were raised
assert(raisedException == null)

// track an unsupported event
analytics.track(UnsupportedEvent())

// assert UnsupportedEventException was raised
assert(raisedException != null)
assert(raisedException is EventNotTrackedException)
assert((raisedException as EventNotTrackedException).cause is UnsupportedEventException)

}


private fun trackTestEvents() {

analytics.track(TestCustomEvent(1))

analytics.setDispatcherEnabled(TestableDispatcher.DispatcherName, false)

analytics.track(TestCustomEvent(2))

analytics.setDispatcherEnabled(TestableDispatcher.DispatcherName, true)

analytics.track(TestCustomEvent(3))

analytics.setKitEnabled(TestKit.instance, false)

analytics.track(TestCustomEvent(4))

analytics.setKitEnabled(TestKit.instance, true)

analytics.track(TestCustomEvent(5))

analytics.track(TestContentViewEvent(1))

}


private fun assertEvents() {


val eventList = dispatcher.eventList

// expect to find 3 custom events , 1 contentview and 1 init event
assert(eventList.size == 5)
assert(eventList[0] is InitDispatcherEvent)
assert((eventList[1] as TestCustomEvent).number == 1)
assert((eventList[2] as TestCustomEvent).number == 3)
assert((eventList[3] as TestCustomEvent).number == 5)
assert((eventList[4] as TestContentViewEvent).number == 1)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package com.sofakingforever.library

import android.app.Application
import com.sofakingforever.library.dispatcher.TestableDispatcher
import com.sofakingforever.library.events.InitDispatcherEvent
import com.sofakingforever.library.events.TestCustomEvent
import org.junit.Test


class DispatcherTest {

private lateinit var raisedException: Exception

@Test
fun testDispatcher() {

val dispatcher = TestableDispatcher()

dispatcher.initDispatcher(Application())

dispatcher.track(TestCustomEvent(1))

dispatcher.track(TestCustomEvent(2))

dispatcher.track(TestCustomEvent(3))

dispatcher.track(TestCustomEvent(4))

dispatcher.track(TestCustomEvent(5))

val eventList = dispatcher.eventList

// expect to find 5 events + init event
assert(eventList.size == 6)
assert(eventList[0] is InitDispatcherEvent)
assert((eventList[1] as TestCustomEvent).number == 1)

// that's enough

}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.sofakingforever.library.dispatcher

import com.sofakingforever.analytics.AnalyticsKit

class TestKit private constructor() : AnalyticsKit {
override val name: String = "Test Kit"

private object Holder {
val INSTANCE = TestKit()
}

companion object {
val instance: TestKit by lazy { Holder.INSTANCE }
}


}
Loading

0 comments on commit 807002b

Please sign in to comment.