Skip to content

Commit 4251415

Browse files
authored
Merge pull request #17127 from wordpress-mobile/issue/17126-shared-login-credentials-analytics
[Jetpack focus] Implement shared login credentials analytics
2 parents 6a5c35f + 67f0866 commit 4251415

File tree

11 files changed

+173
-17
lines changed

11 files changed

+173
-17
lines changed
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package org.wordpress.android.sharedlogin
2+
3+
import org.wordpress.android.analytics.AnalyticsTracker.Stat
4+
import org.wordpress.android.sharedlogin.SharedLoginAnalyticsTracker.ErrorType.Companion.ERROR_TYPE
5+
import org.wordpress.android.util.analytics.AnalyticsTrackerWrapper
6+
import javax.inject.Inject
7+
8+
class SharedLoginAnalyticsTracker @Inject constructor(
9+
private val analyticsTracker: AnalyticsTrackerWrapper
10+
) {
11+
fun trackLoginStart() = analyticsTracker.track(Stat.SHARED_LOGIN_START)
12+
13+
fun trackLoginSuccess() = analyticsTracker.track(Stat.SHARED_LOGIN_SUCCESS)
14+
15+
fun trackLoginFailed(errorType: ErrorType) =
16+
analyticsTracker.track(Stat.SHARED_LOGIN_FAILED, mapOf(ERROR_TYPE to errorType.value))
17+
18+
sealed class ErrorType(val value: String) {
19+
object WPNotLoggedInError : ErrorType("wp_not_logged_in_error")
20+
21+
object QueryTokenError : ErrorType("query_token_error")
22+
23+
companion object {
24+
const val ERROR_TYPE = "error_type"
25+
}
26+
}
27+
}

WordPress/src/main/java/org/wordpress/android/sharedlogin/JetpackPublicData.kt renamed to WordPress/src/main/java/org/wordpress/android/sharedlogin/data/JetpackPublicData.kt

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1-
package org.wordpress.android.sharedlogin
1+
package org.wordpress.android.sharedlogin.data
22

33
import org.wordpress.android.BuildConfig
4-
import org.wordpress.android.sharedlogin.JetpackPublicData.PackageName.Jalapeno
5-
import org.wordpress.android.sharedlogin.JetpackPublicData.PackageName.Vanilla
6-
import org.wordpress.android.sharedlogin.JetpackPublicData.PackageName.Wasabi
7-
import org.wordpress.android.sharedlogin.JetpackPublicData.PublicKeyHash.Debug
8-
import org.wordpress.android.sharedlogin.JetpackPublicData.PublicKeyHash.Release
4+
import org.wordpress.android.sharedlogin.data.JetpackPublicData.PackageName.Jalapeno
5+
import org.wordpress.android.sharedlogin.data.JetpackPublicData.PackageName.Vanilla
6+
import org.wordpress.android.sharedlogin.data.JetpackPublicData.PackageName.Wasabi
7+
import org.wordpress.android.sharedlogin.data.JetpackPublicData.PublicKeyHash.Debug
8+
import org.wordpress.android.sharedlogin.data.JetpackPublicData.PublicKeyHash.Release
99
import javax.inject.Inject
1010

1111
class JetpackPublicData @Inject constructor() {

WordPress/src/main/java/org/wordpress/android/sharedlogin/WordPressPublicData.kt renamed to WordPress/src/main/java/org/wordpress/android/sharedlogin/data/WordPressPublicData.kt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
package org.wordpress.android.sharedlogin
1+
package org.wordpress.android.sharedlogin.data
22

33
import org.wordpress.android.BuildConfig
4-
import org.wordpress.android.sharedlogin.WordPressPublicData.PackageName.Jalapeno
5-
import org.wordpress.android.sharedlogin.WordPressPublicData.PackageName.Vanilla
6-
import org.wordpress.android.sharedlogin.WordPressPublicData.PackageName.Wasabi
4+
import org.wordpress.android.sharedlogin.data.WordPressPublicData.PackageName.Jalapeno
5+
import org.wordpress.android.sharedlogin.data.WordPressPublicData.PackageName.Vanilla
6+
import org.wordpress.android.sharedlogin.data.WordPressPublicData.PackageName.Wasabi
77
import javax.inject.Inject
88

99
class WordPressPublicData @Inject constructor() {

WordPress/src/main/java/org/wordpress/android/sharedlogin/provider/SharedLoginProvider.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import org.wordpress.android.WordPress
66
import org.wordpress.android.fluxc.store.AccountStore
77
import org.wordpress.android.provider.query.QueryContentProvider
88
import org.wordpress.android.provider.query.QueryResult
9-
import org.wordpress.android.sharedlogin.JetpackPublicData
9+
import org.wordpress.android.sharedlogin.data.JetpackPublicData
1010
import org.wordpress.android.util.signature.SignatureNotFoundException
1111
import org.wordpress.android.util.signature.SignatureUtils
1212
import javax.inject.Inject

WordPress/src/main/java/org/wordpress/android/sharedlogin/resolver/SharedLoginResolver.kt

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@ import org.wordpress.android.fluxc.store.AccountStore
77
import org.wordpress.android.provider.query.QueryResult
88
import org.wordpress.android.resolver.ContentResolverWrapper
99
import org.wordpress.android.sharedlogin.JetpackSharedLoginFlag
10-
import org.wordpress.android.sharedlogin.WordPressPublicData
10+
import org.wordpress.android.sharedlogin.SharedLoginAnalyticsTracker
11+
import org.wordpress.android.sharedlogin.SharedLoginAnalyticsTracker.ErrorType
12+
import org.wordpress.android.sharedlogin.data.WordPressPublicData
1113
import org.wordpress.android.sharedlogin.provider.SharedLoginProvider
1214
import org.wordpress.android.ui.main.WPMainActivity
1315
import org.wordpress.android.ui.prefs.AppPrefsWrapper
@@ -24,7 +26,8 @@ class SharedLoginResolver @Inject constructor(
2426
private val accountStore: AccountStore,
2527
private val contentResolverWrapper: ContentResolverWrapper,
2628
private val accountActionBuilderWrapper: AccountActionBuilderWrapper,
27-
private val appPrefsWrapper: AppPrefsWrapper
29+
private val appPrefsWrapper: AppPrefsWrapper,
30+
private val sharedLoginAnalyticsTracker: SharedLoginAnalyticsTracker
2831
) {
2932
fun tryJetpackLogin() {
3033
val isAlreadyLoggedIn = accountStore.accessToken.isNotEmpty()
@@ -33,14 +36,20 @@ class SharedLoginResolver @Inject constructor(
3336
if (isAlreadyLoggedIn || !isFirstTry || !isFeatureFlagEnabled) {
3437
return
3538
}
39+
sharedLoginAnalyticsTracker.trackLoginStart()
3640
appPrefsWrapper.saveIsFirstTrySharedLoginJetpack(false)
3741
val accessTokenResultCursor = getAccessTokenResultCursor()
3842
if (accessTokenResultCursor != null) {
3943
val accessToken = queryResult.getValue<String>(accessTokenResultCursor) ?: ""
4044
if (accessToken.isNotEmpty()) {
45+
sharedLoginAnalyticsTracker.trackLoginSuccess()
4146
dispatchUpdateAccessToken(accessToken)
4247
reloadMainScreen()
48+
} else {
49+
sharedLoginAnalyticsTracker.trackLoginFailed(ErrorType.WPNotLoggedInError)
4350
}
51+
} else {
52+
sharedLoginAnalyticsTracker.trackLoginFailed(ErrorType.QueryTokenError)
4453
}
4554
}
4655

WordPress/src/test/java/org/wordpress/android/sharedlogin/JetpackPublicDataTest.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package org.wordpress.android.sharedlogin
22

33
import org.assertj.core.api.Assertions.assertThat
44
import org.junit.Test
5+
import org.wordpress.android.sharedlogin.data.JetpackPublicData
56

67
class JetpackPublicDataTest {
78
private val classToTest = JetpackPublicData()
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package org.wordpress.android.sharedlogin
2+
3+
import com.nhaarman.mockitokotlin2.mock
4+
import com.nhaarman.mockitokotlin2.verify
5+
import org.junit.Test
6+
import org.wordpress.android.analytics.AnalyticsTracker.Stat
7+
import org.wordpress.android.sharedlogin.SharedLoginAnalyticsTracker.ErrorType
8+
import org.wordpress.android.util.analytics.AnalyticsTrackerWrapper
9+
10+
class SharedLoginAnalyticsTrackerTest {
11+
private val analyticsTrackerWrapper: AnalyticsTrackerWrapper = mock()
12+
private val classToTest = SharedLoginAnalyticsTracker(analyticsTrackerWrapper)
13+
14+
@Test
15+
fun `Should track login start correctly`() {
16+
classToTest.trackLoginStart()
17+
verify(analyticsTrackerWrapper).track(Stat.SHARED_LOGIN_START)
18+
}
19+
20+
@Test
21+
fun `Should track login success correctly`() {
22+
classToTest.trackLoginSuccess()
23+
verify(analyticsTrackerWrapper).track(Stat.SHARED_LOGIN_SUCCESS)
24+
}
25+
26+
@Test
27+
fun `Should track login failed WPNotLoggedInError correctly`() {
28+
classToTest.trackLoginFailed(ErrorType.WPNotLoggedInError)
29+
verify(analyticsTrackerWrapper).track(
30+
Stat.SHARED_LOGIN_FAILED,
31+
mapOf("error_type" to "wp_not_logged_in_error")
32+
)
33+
}
34+
35+
@Test
36+
fun `Should track login failed QueryTokenError correctly`() {
37+
classToTest.trackLoginFailed(ErrorType.QueryTokenError)
38+
verify(analyticsTrackerWrapper).track(
39+
Stat.SHARED_LOGIN_FAILED,
40+
mapOf("error_type" to "query_token_error")
41+
)
42+
}
43+
}

WordPress/src/test/java/org/wordpress/android/sharedlogin/WordPressPublicDataTest.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package org.wordpress.android.sharedlogin
22

33
import org.assertj.core.api.Assertions
44
import org.junit.Test
5+
import org.wordpress.android.sharedlogin.data.WordPressPublicData
56

67
class WordPressPublicDataTest {
78
private val classToTest = WordPressPublicData()

WordPress/src/test/java/org/wordpress/android/sharedlogin/resolver/SharedLoginResolverTest.kt

Lines changed: 69 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package org.wordpress.android.sharedlogin.resolver
33
import android.content.ContentResolver
44
import android.content.Context
55
import android.database.MatrixCursor
6+
import com.nhaarman.mockitokotlin2.any
67
import com.nhaarman.mockitokotlin2.mock
78
import com.nhaarman.mockitokotlin2.never
89
import com.nhaarman.mockitokotlin2.times
@@ -17,7 +18,9 @@ import org.wordpress.android.fluxc.store.AccountStore.UpdateTokenPayload
1718
import org.wordpress.android.provider.query.QueryResult
1819
import org.wordpress.android.resolver.ContentResolverWrapper
1920
import org.wordpress.android.sharedlogin.JetpackSharedLoginFlag
20-
import org.wordpress.android.sharedlogin.WordPressPublicData
21+
import org.wordpress.android.sharedlogin.SharedLoginAnalyticsTracker
22+
import org.wordpress.android.sharedlogin.SharedLoginAnalyticsTracker.ErrorType
23+
import org.wordpress.android.sharedlogin.data.WordPressPublicData
2124
import org.wordpress.android.sharedlogin.provider.SharedLoginProvider
2225
import org.wordpress.android.ui.prefs.AppPrefsWrapper
2326
import org.wordpress.android.util.AccountActionBuilderWrapper
@@ -33,6 +36,7 @@ class SharedLoginResolverTest {
3336
private val contentResolverWrapper: ContentResolverWrapper = mock()
3437
private val accountActionBuilderWrapper: AccountActionBuilderWrapper = mock()
3538
private val appPrefsWrapper: AppPrefsWrapper = mock()
39+
private val sharedLoginAnalyticsTracker: SharedLoginAnalyticsTracker = mock()
3640
private val classToTest = SharedLoginResolver(
3741
jetpackSharedLoginFlag,
3842
contextProvider,
@@ -42,7 +46,8 @@ class SharedLoginResolverTest {
4246
accountStore,
4347
contentResolverWrapper,
4448
accountActionBuilderWrapper,
45-
appPrefsWrapper
49+
appPrefsWrapper,
50+
sharedLoginAnalyticsTracker
4651
)
4752
private val loggedInToken = "valid"
4853
private val notLoggedInToken = ""
@@ -110,7 +115,68 @@ class SharedLoginResolverTest {
110115
featureEnabled()
111116
whenever(queryResult.getValue<String>(mockCursor)).thenReturn(notLoggedInToken)
112117
classToTest.tryJetpackLogin()
113-
verify(dispatcher, times(0)).dispatch(updateTokenAction)
118+
verify(dispatcher, never()).dispatch(updateTokenAction)
119+
}
120+
121+
@Test
122+
fun `Should track login start if NOT already logged in, feature flag is ENABLED and IS first try`() {
123+
featureEnabled()
124+
classToTest.tryJetpackLogin()
125+
verify(sharedLoginAnalyticsTracker).trackLoginStart()
126+
}
127+
128+
@Test
129+
fun `Should NOT track login start if IS already logged in`() {
130+
whenever(appPrefsWrapper.getIsFirstTrySharedLoginJetpack()).thenReturn(true)
131+
whenever(accountStore.accessToken).thenReturn(loggedInToken)
132+
whenever(jetpackSharedLoginFlag.isEnabled()).thenReturn(true)
133+
classToTest.tryJetpackLogin()
134+
verify(sharedLoginAnalyticsTracker, never()).trackLoginStart()
135+
}
136+
137+
@Test
138+
fun `Should NOT track login start if feature flag is DISABLED`() {
139+
whenever(appPrefsWrapper.getIsFirstTrySharedLoginJetpack()).thenReturn(true)
140+
whenever(accountStore.accessToken).thenReturn(notLoggedInToken)
141+
whenever(jetpackSharedLoginFlag.isEnabled()).thenReturn(false)
142+
classToTest.tryJetpackLogin()
143+
verify(sharedLoginAnalyticsTracker, never()).trackLoginStart()
144+
}
145+
146+
@Test
147+
fun `Should NOT track login start if IS NOT the first try`() {
148+
whenever(appPrefsWrapper.getIsFirstTrySharedLoginJetpack()).thenReturn(false)
149+
whenever(accountStore.accessToken).thenReturn(notLoggedInToken)
150+
whenever(jetpackSharedLoginFlag.isEnabled()).thenReturn(true)
151+
classToTest.tryJetpackLogin()
152+
verify(sharedLoginAnalyticsTracker, never()).trackLoginStart()
153+
}
154+
155+
@Test
156+
fun `Should track login failed if access token result cursor IS null`() {
157+
whenever(contentResolverWrapper.queryUri(contentResolver, uriValue)).thenReturn(null)
158+
featureEnabled()
159+
classToTest.tryJetpackLogin()
160+
verify(sharedLoginAnalyticsTracker, never()).trackLoginSuccess()
161+
verify(sharedLoginAnalyticsTracker, times(1)).trackLoginFailed(ErrorType.QueryTokenError)
162+
}
163+
164+
@Test
165+
fun `Should track login failed if access token IS empty`() {
166+
featureEnabled()
167+
whenever(queryResult.getValue<String>(mockCursor)).thenReturn(notLoggedInToken)
168+
classToTest.tryJetpackLogin()
169+
verify(sharedLoginAnalyticsTracker, never()).trackLoginSuccess()
170+
verify(sharedLoginAnalyticsTracker, times(1)).trackLoginFailed(ErrorType.WPNotLoggedInError)
171+
}
172+
173+
@Test
174+
fun `Should track login success if access token result cursor IS NOT null AND access token IS NOT empty`() {
175+
featureEnabled()
176+
whenever(queryResult.getValue<String>(mockCursor)).thenReturn(loggedInToken)
177+
classToTest.tryJetpackLogin()
178+
verify(sharedLoginAnalyticsTracker, never()).trackLoginFailed(any())
179+
verify(sharedLoginAnalyticsTracker, times(1)).trackLoginSuccess()
114180
}
115181

116182
private fun featureEnabled() {

libs/analytics/src/main/java/org/wordpress/android/analytics/AnalyticsTracker.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -945,7 +945,10 @@ public enum Stat {
945945
JETPACK_POWERED_BANNER_TAPPED,
946946
JETPACK_POWERED_BADGE_TAPPED,
947947
JETPACK_POWERED_BOTTOM_SHEET_GET_JETPACK_APP_TAPPED,
948-
JETPACK_POWERED_BOTTOM_SHEET_CONTINUE_TAPPED
948+
JETPACK_POWERED_BOTTOM_SHEET_CONTINUE_TAPPED,
949+
SHARED_LOGIN_START,
950+
SHARED_LOGIN_SUCCESS,
951+
SHARED_LOGIN_FAILED
949952
}
950953

951954
private static final List<Tracker> TRACKERS = new ArrayList<>();

0 commit comments

Comments
 (0)